00001 /*- 00002 * See the file LICENSE for redistribution information. 00003 * 00004 * Copyright (c) 2000 00005 * Sleepycat Software. All rights reserved. 00006 * 00007 * $Id: db__vrfy_8c-source.html,v 1.1 2008年06月08日 10:18:28 sebdiaz Exp $ 00008 */ 00009 00010 #include "config.h" 00011 00012 #ifndef lint 00013 static const char revid[] = "$Id: db__vrfy_8c-source.html,v 1.1 2008年06月08日 10:18:28 sebdiaz Exp $"; 00014 #endif /* not lint */ 00015 00016 #ifndef NO_SYSTEM_INCLUDES 00017 #include <sys/types.h> 00018 00019 #include <errno.h> 00020 #include <string.h> 00021 #endif 00022 00023 #include "db_int.h" 00024 #include "db_page.h" 00025 #include "db_swap.h" 00026 #include "db_verify.h" 00027 #include "db_ext.h" 00028 #include "btree.h" 00029 #include "hash.h" 00030 #include "qam.h" 00031 00032 static int __db_guesspgsize __P((DB_ENV *, DB_FH *)); 00033 static int __db_is_valid_magicno __P((u_int32_t, DBTYPE *)); 00034 static int __db_is_valid_pagetype __P((u_int32_t)); 00035 static int __db_meta2pgset 00036 __P((DB *, VRFY_DBINFO *, db_pgno_t, u_int32_t, DB *)); 00037 static int __db_salvage_subdbs 00038 __P((DB *, VRFY_DBINFO *, void *, 00039 int(*)(void *, const void *), u_int32_t, int *)); 00040 static int __db_salvage_unknowns 00041 __P((DB *, VRFY_DBINFO *, void *, 00042 int (*)(void *, const void *), u_int32_t)); 00043 static int __db_vrfy_common 00044 __P((DB *, VRFY_DBINFO *, PAGE *, db_pgno_t, u_int32_t)); 00045 static int __db_vrfy_freelist __P((DB *, VRFY_DBINFO *, db_pgno_t, u_int32_t)); 00046 static int __db_vrfy_invalid 00047 __P((DB *, VRFY_DBINFO *, PAGE *, db_pgno_t, u_int32_t)); 00048 static int __db_vrfy_orderchkonly __P((DB *, 00049 VRFY_DBINFO *, const char *, const char *, u_int32_t)); 00050 static int __db_vrfy_pagezero __P((DB *, VRFY_DBINFO *, DB_FH *, u_int32_t)); 00051 static int __db_vrfy_subdbs __P((DB *, VRFY_DBINFO *, char *, u_int32_t)); 00052 static int __db_vrfy_structure 00053 __P((DB *, VRFY_DBINFO *, char *, db_pgno_t, u_int32_t)); 00054 static int __db_vrfy_walkpages 00055 __P((DB *, VRFY_DBINFO *, void *, int (*)(void *, const void *), 00056 u_int32_t)); 00057 00058 /* 00059 * This is the code for DB->verify, the DB database consistency checker. 00060 * For now, it checks all subdatabases in a database, and verifies 00061 * everything it knows how to (i.e. it's all-or-nothing, and one can't 00062 * check only for a subset of possible problems). 00063 */ 00064 00065 /* 00066 * CDB___db_verify -- 00067 * Walk the entire file page-by-page, either verifying with or without 00068 * dumping in db_dump -d format, or DB_SALVAGE-ing whatever key/data 00069 * pairs can be found and dumping them in standard (db_load-ready) 00070 * dump format. 00071 * 00072 * (Salvaging isn't really a verification operation, but we put it 00073 * here anyway because it requires essentially identical top-level 00074 * code.) 00075 * 00076 * flags may be 0, DB_NOORDERCHK, DB_ORDERCHKONLY, or DB_SALVAGE 00077 * (and optionally DB_AGGRESSIVE). 00078 * 00079 * CDB___db_verify itself is simply a wrapper to CDB___db_verify_internal, 00080 * which lets us pass appropriate equivalents to FILE * in from the 00081 * non-C APIs. 00082 * 00083 * PUBLIC: int CDB___db_verify 00084 * PUBLIC: __P((DB *, const char *, const char *, FILE *, u_int32_t)); 00085 */ 00086 int 00087 CDB___db_verify(dbp, file, database, outfile, flags) 00088 DB *dbp; 00089 const char *file, *database; 00090 FILE *outfile; 00091 u_int32_t flags; 00092 { 00093 00094 return (CDB___db_verify_internal(dbp, 00095 file, database, outfile, CDB___db_verify_callback, flags)); 00096 } 00097 00098 /* 00099 * CDB___db_verify_callback -- 00100 * Callback function for using pr_* functions from C. 00101 * 00102 * PUBLIC: int CDB___db_verify_callback __P((void *, const void *)); 00103 */ 00104 int 00105 CDB___db_verify_callback(handle, str_arg) 00106 void *handle; 00107 const void *str_arg; 00108 { 00109 char *str; 00110 FILE *f; 00111 00112 str = (char *)str_arg; 00113 f = (FILE *)handle; 00114 00115 if (fprintf(f, str) != (int)strlen(str)) 00116 return (EIO); 00117 00118 return (0); 00119 } 00120 00121 /* 00122 * CDB___db_verify_internal -- 00123 * Inner meat of CDB___db_verify. 00124 * 00125 * PUBLIC: int CDB___db_verify_internal __P((DB *, const char *, 00126 * PUBLIC: const char *, void *, int (*)(void *, const void *), u_int32_t)); 00127 */ 00128 int 00129 CDB___db_verify_internal(dbp_orig, name, subdb, handle, callback, flags) 00130 DB *dbp_orig; 00131 const char *name, *subdb; 00132 void *handle; 00133 int (*callback) __P((void *, const void *)); 00134 u_int32_t flags; 00135 { 00136 DB *dbp; 00137 DB_ENV *dbenv; 00138 DB_FH fh, *fhp; 00139 PAGE *h; 00140 VRFY_DBINFO *vdp; 00141 db_pgno_t last; 00142 int has, ret, isbad; 00143 char *real_name; 00144 00145 dbenv = dbp_orig->dbenv; 00146 vdp = NULL; 00147 real_name = NULL; 00148 ret = isbad = 0; 00149 00150 memset(&fh, 0, sizeof(fh)); 00151 fhp = &fh; 00152 00153 PANIC_CHECK(dbenv); 00154 DB_ILLEGAL_AFTER_OPEN(dbp_orig, "verify"); 00155 00156 #define OKFLAGS (DB_AGGRESSIVE | DB_NOORDERCHK | DB_ORDERCHKONLY | DB_SALVAGE) 00157 if ((ret = CDB___db_fchk(dbenv, "DB->verify", flags, OKFLAGS)) != 0) 00158 return (ret); 00159 00160 /* 00161 * DB_SALVAGE is mutually exclusive with the other flags except 00162 * DB_AGGRESSIVE. 00163 */ 00164 if (LF_ISSET(DB_SALVAGE) && 00165 (flags & ~DB_AGGRESSIVE) != DB_SALVAGE) 00166 return (CDB___db_ferr(dbenv, "CDB___db_verify", 1)); 00167 00168 if (LF_ISSET(DB_ORDERCHKONLY) && flags != DB_ORDERCHKONLY) 00169 return (CDB___db_ferr(dbenv, "CDB___db_verify", 1)); 00170 00171 if (LF_ISSET(DB_ORDERCHKONLY) && subdb == NULL) { 00172 CDB___db_err(dbenv, "DB_ORDERCHKONLY requires a database name"); 00173 return (EINVAL); 00174 } 00175 00176 /* 00177 * Forbid working in an environment that uses transactions or 00178 * locking; we're going to be looking at the file freely, 00179 * and while we're not going to modify it, we aren't obeying 00180 * locking conventions either. 00181 */ 00182 if (TXN_ON(dbenv) || LOCKING_ON(dbenv) || LOGGING_ON(dbenv)) { 00183 dbp_orig->errx(dbp_orig, 00184 "verify may not be used with transactions, logging, or locking"); 00185 return (EINVAL); 00186 /* NOTREACHED */ 00187 } 00188 00189 /* Create a dbp to use internally, which we can close at our leisure. */ 00190 if ((ret = CDB_db_create(&dbp, dbenv, 0)) != 0) 00191 goto err; 00192 00193 /* Copy the supplied pagesize, which we use if the file one is bogus. */ 00194 if (dbp_orig->pgsize >= DB_MIN_PGSIZE && 00195 dbp_orig->pgsize <= DB_MAX_PGSIZE) 00196 dbp->set_pagesize(dbp, dbp_orig->pgsize); 00197 00198 /* 00199 * We don't know how large the cache is, and if the database 00200 * in question uses a small page size--which we don't know 00201 * yet!--it may be uncomfortably small for the default page 00202 * size [#2143]. However, the things we need temporary 00203 * databases for in dbinfo are largely tiny, so using a 00204 * 1024-byte pagesize is probably not going to be a big hit, 00205 * and will make us fit better into small spaces. 00206 */ 00207 if ((ret = CDB___db_vrfy_dbinfo_create(dbenv, 1024, &vdp)) != 0) 00208 goto err; 00209 00210 /* Find the real name of the file. */ 00211 if ((ret = CDB___db_appname(dbenv, 00212 DB_APP_DATA, NULL, name, 0, NULL, &real_name)) != 0) 00213 goto err; 00214 00215 /* 00216 * Our first order of business is to verify page 0, which is 00217 * the metadata page for the master database of subdatabases 00218 * or of the only database in the file. We want to do this by hand 00219 * rather than just calling CDB___db_open in case it's corrupt--various 00220 * things in CDB___db_open might act funny. 00221 * 00222 * Once we know the metadata page is healthy, I believe that it's 00223 * safe to open the database normally and then use the page swapping 00224 * code, which makes life easier. 00225 */ 00226 if ((ret = CDB___os_open(dbenv, real_name, DB_OSO_RDONLY, 0444, fhp)) != 0) 00227 goto err; 00228 00229 /* Verify the metadata page 0; set pagesize and type. */ 00230 if ((ret = __db_vrfy_pagezero(dbp, vdp, fhp, flags)) != 0) { 00231 if (ret == DB_VERIFY_BAD) 00232 isbad = 1; 00233 else 00234 goto err; 00235 } 00236 00237 /* 00238 * We can assume at this point that dbp->pagesize and dbp->type are 00239 * set correctly, or at least as well as they can be, and that 00240 * locking, logging, and txns are not in use. Thus we can trust 00241 * the memp code not to look at the page, and thus to be safe 00242 * enough to use. 00243 * 00244 * The dbp is not open, but the file is open in the fhp, and we 00245 * cannot assume that CDB___db_open is safe. Call CDB___db_dbenv_setup, 00246 * the [safe] part of CDB___db_open that initializes the environment-- 00247 * and the mpool--manually. 00248 */ 00249 if ((ret = CDB___db_dbenv_setup(dbp, 00250 name, DB_ODDFILESIZE | DB_RDONLY)) != 0) 00251 return (ret); 00252 00253 /* 00254 * Find out the page number of the last page in the database. 00255 * 00256 * XXX: This currently fails if the last page is of bad type, 00257 * because it calls CDB___db_pgin and that pukes. This is bad. 00258 */ 00259 if ((ret = CDB_memp_fget(dbp->mpf, &last, DB_MPOOL_LAST, &h)) != 0) 00260 goto err; 00261 if ((ret = CDB_memp_fput(dbp->mpf, h, 0)) != 0) 00262 goto err; 00263 00264 vdp->last_pgno = last; 00265 00266 /* 00267 * DB_ORDERCHKONLY is a special case; our file consists of 00268 * several subdatabases, which use different hash, bt_compare, 00269 * and/or dup_compare functions. Consequently, we couldn't verify 00270 * sorting and hashing simply by calling DB->verify() on the file. 00271 * DB_ORDERCHKONLY allows us to come back and check those things; it 00272 * requires a subdatabase, and assumes that everything but that 00273 * database's sorting/hashing is correct. 00274 */ 00275 if (LF_ISSET(DB_ORDERCHKONLY)) { 00276 ret = __db_vrfy_orderchkonly(dbp, vdp, name, subdb, flags); 00277 goto done; 00278 } 00279 00280 /* 00281 * When salvaging, we use a db to keep track of whether we've seen a 00282 * given overflow or dup page in the course of traversing normal data. 00283 * If in the end we have not, we assume its key got lost and print it 00284 * with key "UNKNOWN". 00285 */ 00286 if (LF_ISSET(DB_SALVAGE)) { 00287 if ((ret = CDB___db_salvage_init(vdp)) != 0) 00288 return (ret); 00289 00290 /* 00291 * If we're not being aggressive, attempt to crack subdbs. 00292 * "has" will indicate whether the attempt has succeeded 00293 * (even in part), meaning that we have some semblance of 00294 * subdbs; on the walkpages pass, we print out 00295 * whichever data pages we have not seen. 00296 */ 00297 has = 0; 00298 if (!LF_ISSET(DB_AGGRESSIVE) && (__db_salvage_subdbs(dbp, 00299 vdp, handle, callback, flags, &has)) != 0) 00300 isbad = 1; 00301 00302 /* 00303 * If we have subdatabases, we need to signal that if 00304 * any keys are found that don't belong to a subdatabase, 00305 * they'll need to have an "__OTHER__" subdatabase header 00306 * printed first. Flag this. Else, print a header for 00307 * the normal, non-subdb database. 00308 */ 00309 if (has == 1) 00310 F_SET(vdp, SALVAGE_PRINTHEADER); 00311 else if ((ret = CDB___db_prheader(dbp, 00312 NULL, 0, 0, handle, callback, vdp, PGNO_BASE_MD)) != 0) 00313 goto err; 00314 } 00315 00316 if ((ret = 00317 __db_vrfy_walkpages(dbp, vdp, handle, callback, flags)) != 0) { 00318 if (ret == DB_VERIFY_BAD) 00319 isbad = 1; 00320 else if (ret != 0) 00321 goto err; 00322 } 00323 00324 /* If we're verifying, verify inter-page structure. */ 00325 if (!LF_ISSET(DB_SALVAGE) && isbad == 0) 00326 if ((ret = 00327 __db_vrfy_structure(dbp, vdp, real_name, 0, flags)) != 0) { 00328 if (ret == DB_VERIFY_BAD) 00329 isbad = 1; 00330 else if (ret != 0) 00331 goto err; 00332 } 00333 00334 /* 00335 * If we're salvaging, output with key UNKNOWN any overflow or dup pages 00336 * we haven't been able to put in context. Then destroy the salvager's 00337 * state-saving database. 00338 */ 00339 if (LF_ISSET(DB_SALVAGE)) { 00340 if ((ret = __db_salvage_unknowns(dbp, 00341 vdp, handle, callback, flags)) != 0) 00342 isbad = 1; 00343 /* No return value, since there's little we can do. */ 00344 CDB___db_salvage_destroy(vdp); 00345 } 00346 00347 if (0) { 00348 err: (void)CDB___db_err(dbenv, "%s: %s", name, CDB_db_strerror(ret)); 00349 } 00350 00351 if (LF_ISSET(DB_SALVAGE) && 00352 (has == 0 || F_ISSET(vdp, SALVAGE_PRINTFOOTER))) 00353 (void)CDB___db_prfooter(handle, callback); 00354 00355 done: if (F_ISSET(fhp, DB_FH_VALID)) 00356 (void)CDB___os_closehandle(fhp); 00357 if (dbp) 00358 (void)dbp->close(dbp, 0); 00359 if (vdp) 00360 (void)CDB___db_vrfy_dbinfo_destroy(vdp); 00361 if (real_name) 00362 CDB___os_freestr(real_name); 00363 00364 if ((ret == 0 && isbad == 1) || ret == DB_VERIFY_FATAL) 00365 ret = DB_VERIFY_BAD; 00366 00367 return (ret); 00368 } 00369 00370 /* 00371 * __db_vrfy_pagezero -- 00372 * Verify the master metadata page. Use seek, read, and a local buffer 00373 * rather than the DB paging code, for safety. 00374 * 00375 * Must correctly (or best-guess) set dbp->type and dbp->pagesize. 00376 */ 00377 static int 00378 __db_vrfy_pagezero(dbp, vdp, fhp, flags) 00379 DB *dbp; 00380 VRFY_DBINFO *vdp; 00381 DB_FH *fhp; 00382 u_int32_t flags; 00383 { 00384 DBMETA *meta; 00385 DB_ENV *dbenv; 00386 VRFY_PAGEINFO *pip; 00387 db_pgno_t freelist; 00388 int t_ret, ret, nr, swapped; 00389 u_int8_t mbuf[DBMETASIZE]; 00390 00391 swapped = ret = t_ret = 0; 00392 freelist = 0; 00393 dbenv = dbp->dbenv; 00394 meta = (DBMETA *)mbuf; 00395 dbp->type = DB_UNKNOWN; 00396 00397 /* 00398 * Seek to the metadata page. 00399 * Note that if we're just starting a verification, dbp->pgsize 00400 * may be zero; this is okay, as we want page zero anyway and 00401 * 0*0 == 0. 00402 */ 00403 if ((ret = CDB___os_seek(dbenv, fhp, 0, 0, 0, 0, DB_OS_SEEK_SET)) != 0) 00404 goto err; 00405 00406 if ((ret = CDB___os_read(dbenv, fhp, mbuf, DBMETASIZE, (size_t *)&nr)) != 0) 00407 goto err; 00408 00409 if (nr != DBMETASIZE) { 00410 EPRINT((dbp->dbenv, 00411 "Incomplete metadata page %lu", PGNO_BASE_MD)); 00412 t_ret = DB_VERIFY_FATAL; 00413 goto err; 00414 } 00415 00416 /* 00417 * Check all of the fields that we can. 00418 */ 00419 00420 /* 08-11: Current page number. Must == pgno. */ 00421 /* Note that endianness doesn't matter--it's zero. */ 00422 if (meta->pgno != PGNO_BASE_MD) { 00423 EPRINT((dbp->dbenv, "Bad pgno: was %lu, should be %lu", 00424 meta->pgno, PGNO_BASE_MD)); 00425 ret = DB_VERIFY_BAD; 00426 } 00427 00428 /* 12-15: Magic number. Must be one of valid set. */ 00429 if (__db_is_valid_magicno(meta->magic, &dbp->type)) 00430 swapped = 0; 00431 else { 00432 M_32_SWAP(meta->magic); 00433 if (__db_is_valid_magicno(meta->magic, 00434 &dbp->type)) 00435 swapped = 1; 00436 else { 00437 EPRINT((dbp->dbenv, "Bad magic no.: %lu", meta->magic)); 00438 ret = DB_VERIFY_BAD; 00439 } 00440 } 00441 00442 /* 00443 * 16-19: Version. Must be current; for now, we 00444 * don't support verification of old versions. 00445 */ 00446 if (swapped) 00447 M_32_SWAP(meta->version); 00448 if ((dbp->type == DB_BTREE && meta->version != DB_BTREEVERSION) || 00449 (dbp->type == DB_HASH && meta->version != DB_HASHVERSION) || 00450 (dbp->type == DB_QUEUE && meta->version != DB_QAMVERSION)) { 00451 ret = DB_VERIFY_BAD; 00452 EPRINT((dbp->dbenv, "%s%s", "Old or incorrect DB ", 00453 "version; extraneous errors may result")); 00454 } 00455 00456 /* 00457 * 20-23: Pagesize. Must be power of two, 00458 * greater than 512, and less than 64K. 00459 */ 00460 if (swapped) 00461 M_32_SWAP(meta->pagesize); 00462 if (IS_VALID_PAGESIZE(meta->pagesize)) 00463 dbp->pgsize = meta->pagesize; 00464 else { 00465 EPRINT((dbp->dbenv, "Bad page size: %lu", 00466 meta->pagesize)); 00467 ret = DB_VERIFY_BAD; 00468 00469 /* 00470 * Now try to settle on a pagesize to use. 00471 * If the user-supplied one is reasonable, 00472 * use it; else, guess. 00473 */ 00474 if (!IS_VALID_PAGESIZE(dbp->pgsize)) 00475 dbp->pgsize = __db_guesspgsize(dbenv, fhp); 00476 } 00477 00478 /* 00479 * 25: Page type. Must be correct for dbp->type, 00480 * which is by now set as well as it can be. 00481 */ 00482 /* Needs no swapping--only one byte! */ 00483 if ((dbp->type == DB_BTREE && meta->type != P_BTREEMETA) || 00484 (dbp->type == DB_HASH && meta->type != P_HASHMETA) || 00485 (dbp->type == DB_QUEUE && meta->type != P_QAMMETA)) { 00486 ret = DB_VERIFY_BAD; 00487 EPRINT((dbp->dbenv, "Bad page type: %lu", meta->type)); 00488 } 00489 00490 /* 00491 * 28-31: Free list page number. 00492 * We'll verify its sensibility when we do inter-page 00493 * verification later; for now, just store it. 00494 */ 00495 if (swapped) 00496 M_32_SWAP(meta->free); 00497 freelist = meta->free; 00498 00499 /* 00500 * Initialize vdp->pages to fit a single pageinfo structure for 00501 * this one page. We'll realloc later when we know how many 00502 * pages there are. 00503 */ 00504 if ((ret = CDB___db_vrfy_getpageinfo(vdp, PGNO_BASE_MD, &pip)) != 0) 00505 return (ret); 00506 pip->pgno = PGNO_BASE_MD; 00507 pip->type = meta->type; 00508 00509 /* 00510 * Signal that we still have to check the info specific to 00511 * a given type of meta page. 00512 */ 00513 F_SET(pip, VRFY_INCOMPLETE); 00514 00515 pip->free = freelist; 00516 00517 if ((ret = CDB___db_vrfy_putpageinfo(vdp, pip)) != 0) 00518 return (ret); 00519 00520 if (0) { 00521 err: CDB___db_err(dbenv, "%s", CDB_db_strerror(ret)); 00522 } 00523 00524 if (swapped == 1) 00525 F_SET(dbp, DB_AM_SWAP); 00526 if (t_ret != 0) 00527 ret = t_ret; 00528 return (ret); 00529 } 00530 00531 /* 00532 * __db_vrfy_walkpages -- 00533 * Main loop of the verifier/salvager. Walks through, 00534 * page by page, and verifies all pages and/or prints all data pages. 00535 */ 00536 static int 00537 __db_vrfy_walkpages(dbp, vdp, handle, callback, flags) 00538 DB *dbp; 00539 VRFY_DBINFO *vdp; 00540 void *handle; 00541 int (*callback) __P((void *, const void *)); 00542 u_int32_t flags; 00543 { 00544 DB_ENV *dbenv; 00545 PAGE *h; 00546 db_pgno_t i; 00547 int ret, t_ret, isbad; 00548 00549 ret = isbad = t_ret = 0; 00550 dbenv = dbp->dbenv; 00551 00552 if ((ret = CDB___db_fchk(dbenv, 00553 "__db_vrfy_walkpages", flags, OKFLAGS)) != 0) 00554 return (ret); 00555 00556 for (i = 0; i <= vdp->last_pgno; i++) { 00557 /* 00558 * If DB_SALVAGE is set, we inspect our database of 00559 * completed pages, and skip any we've already printed in 00560 * the subdb pass. 00561 */ 00562 if (LF_ISSET(DB_SALVAGE) && (CDB___db_salvage_isdone(vdp, i) != 0)) 00563 continue; 00564 00565 /* If an individual page get fails, keep going. */ 00566 if ((t_ret = CDB_memp_fget(dbp->mpf, &i, 0, &h)) != 0) { 00567 if (ret == 0) 00568 ret = t_ret; 00569 continue; 00570 } 00571 00572 if (LF_ISSET(DB_SALVAGE)) { 00573 /* 00574 * We pretty much don't want to quit unless a 00575 * bomb hits. May as well return that something 00576 * was screwy, however. 00577 */ 00578 if ((t_ret = CDB___db_salvage(dbp, 00579 vdp, i, h, handle, callback, flags)) != 0) { 00580 if (ret == 0) 00581 ret = t_ret; 00582 isbad = 1; 00583 } 00584 } else { 00585 /* 00586 * Verify info common to all page 00587 * types. 00588 */ 00589 if (i != PGNO_BASE_MD) 00590 if ((t_ret = __db_vrfy_common(dbp, 00591 vdp, h, i, flags)) == DB_VERIFY_BAD) 00592 isbad = 1; 00593 00594 switch (TYPE(h)) { 00595 case P_INVALID: 00596 t_ret = __db_vrfy_invalid(dbp, 00597 vdp, h, i, flags); 00598 break; 00599 case __P_DUPLICATE: 00600 isbad = 1; 00601 EPRINT((dbp->dbenv, 00602 "Old-style dup page %lu", i)); 00603 break; 00604 case P_HASH: 00605 t_ret = CDB___ham_vrfy(dbp, 00606 vdp, h, i, flags); 00607 break; 00608 case P_IBTREE: 00609 case P_IRECNO: 00610 case P_LBTREE: 00611 case P_LDUP: 00612 t_ret = CDB___bam_vrfy(dbp, 00613 vdp, h, i, flags); 00614 break; 00615 case P_LRECNO: 00616 t_ret = CDB___ram_vrfy_leaf(dbp, 00617 vdp, h, i, flags); 00618 break; 00619 case P_OVERFLOW: 00620 t_ret = CDB___db_vrfy_overflow(dbp, 00621 vdp, h, i, flags); 00622 break; 00623 case P_HASHMETA: 00624 t_ret = CDB___ham_vrfy_meta(dbp, 00625 vdp, (HMETA *)h, i, flags); 00626 break; 00627 case P_BTREEMETA: 00628 t_ret = CDB___bam_vrfy_meta(dbp, 00629 vdp, (BTMETA *)h, i, flags); 00630 break; 00631 case P_QAMMETA: 00632 t_ret = CDB___qam_vrfy_meta(dbp, 00633 vdp, (QMETA *)h, i, flags); 00634 break; 00635 case P_QAMDATA: 00636 t_ret = CDB___qam_vrfy_data(dbp, 00637 vdp, (QPAGE *)h, i, flags); 00638 break; 00639 default: 00640 EPRINT((dbp->dbenv, 00641 "Unknown page type: %lu", TYPE(h))); 00642 isbad = 1; 00643 break; 00644 } 00645 00646 /* 00647 * Set up error return. 00648 */ 00649 if (t_ret == DB_VERIFY_BAD) 00650 isbad = 1; 00651 else if (t_ret == DB_VERIFY_FATAL) 00652 goto err; 00653 else 00654 ret = t_ret; 00655 } 00656 00657 if ((t_ret = CDB_memp_fput(dbp->mpf, h, 0)) != 0 && ret == 0) 00658 ret = t_ret; 00659 } 00660 00661 if (0) { 00662 err: if ((t_ret = CDB_memp_fput(dbp->mpf, h, 0)) != 0) 00663 return (ret == 0 ? t_ret : ret); 00664 return (DB_VERIFY_BAD); 00665 } 00666 00667 return ((isbad == 1 && ret == 0) ? DB_VERIFY_BAD : ret); 00668 } 00669 00670 /* 00671 * __db_vrfy_structure-- 00672 * After a beginning-to-end walk through the database has been 00673 * completed, put together the information that has been collected 00674 * to verify the overall database structure. 00675 * 00676 * Should only be called if we want to do a database verification, 00677 * i.e. if DB_SALVAGE is not set. 00678 */ 00679 static int 00680 __db_vrfy_structure(dbp, vdp, dbname, meta_pgno, flags) 00681 DB *dbp; 00682 VRFY_DBINFO *vdp; 00683 char *dbname; 00684 db_pgno_t meta_pgno; 00685 u_int32_t flags; 00686 { 00687 DB *pgset; 00688 DB_ENV *dbenv; 00689 VRFY_PAGEINFO *pip; 00690 db_pgno_t i; 00691 int ret, isbad, hassubs, p; 00692 00693 isbad = 0; 00694 pip = NULL; 00695 dbenv = dbp->dbenv; 00696 pgset = vdp->pgset; 00697 00698 if ((ret = CDB___db_fchk(dbenv, "DB->verify", flags, OKFLAGS)) != 0) 00699 return (ret); 00700 if (LF_ISSET(DB_SALVAGE)) { 00701 CDB___db_err(dbenv, "__db_vrfy_structure called with DB_SALVAGE"); 00702 return (EINVAL); 00703 } 00704 00705 /* 00706 * Call the appropriate function to downwards-traverse the db type. 00707 */ 00708 switch(dbp->type) { 00709 case DB_BTREE: 00710 case DB_RECNO: 00711 if ((ret = CDB___bam_vrfy_structure(dbp, vdp, 0, flags)) != 0) { 00712 if (ret == DB_VERIFY_BAD) 00713 isbad = 1; 00714 else 00715 goto err; 00716 } 00717 00718 /* 00719 * If we have subdatabases and we know that the database is, 00720 * thus far, sound, it's safe to walk the tree of subdatabases. 00721 * Do so, and verify the structure of the databases within. 00722 */ 00723 if ((ret = CDB___db_vrfy_getpageinfo(vdp, 0, &pip)) != 0) 00724 goto err; 00725 hassubs = F_ISSET(pip, VRFY_HAS_SUBDBS); 00726 if ((ret = CDB___db_vrfy_putpageinfo(vdp, pip)) != 0) 00727 goto err; 00728 00729 if (isbad == 0 && hassubs) 00730 if ((ret = 00731 __db_vrfy_subdbs(dbp, vdp, dbname, flags)) != 0) { 00732 if (ret == DB_VERIFY_BAD) 00733 isbad = 1; 00734 else 00735 goto err; 00736 } 00737 break; 00738 case DB_HASH: 00739 if ((ret = CDB___ham_vrfy_structure(dbp, vdp, 0, flags)) != 0) { 00740 if (ret == DB_VERIFY_BAD) 00741 isbad = 1; 00742 else 00743 goto err; 00744 } 00745 break; 00746 case DB_QUEUE: 00747 if ((ret = CDB___qam_vrfy_structure(dbp, vdp, flags)) != 0) { 00748 if (ret == DB_VERIFY_BAD) 00749 isbad = 1; 00750 } 00751 00752 /* 00753 * Queue pages may be unreferenced and totally zeroed, if 00754 * they're empty; queue doesn't have much structure, so 00755 * this is unlikely to be wrong in any troublesome sense. 00756 * Skip to "err". 00757 */ 00758 goto err; 00759 /* NOTREACHED */ 00760 default: 00761 /* This should only happen if the verifier is somehow broken. */ 00762 DB_ASSERT(0); 00763 ret = EINVAL; 00764 goto err; 00765 /* NOTREACHED */ 00766 } 00767 00768 /* Walk free list. */ 00769 if ((ret = 00770 __db_vrfy_freelist(dbp, vdp, meta_pgno, flags)) == DB_VERIFY_BAD) 00771 isbad = 1; 00772 00773 /* 00774 * If structure checks up until now have failed, it's likely that 00775 * checking what pages have been missed will result in oodles of 00776 * extraneous error messages being EPRINTed. Skip to the end 00777 * if this is the case; we're going to be printing at least one 00778 * error anyway, and probably all the more salient ones. 00779 */ 00780 if (ret != 0 || isbad == 1) 00781 goto err; 00782 00783 /* 00784 * Make sure no page has been missed and that no page is still marked 00785 * "all zeroes" (only certain hash pages can be, and they're unmarked 00786 * in CDB___ham_vrfy_structure). 00787 */ 00788 for (i = 0; i < vdp->last_pgno + 1; i++) { 00789 if ((ret = CDB___db_vrfy_getpageinfo(vdp, i, &pip)) != 0) 00790 goto err; 00791 if ((ret = CDB___db_vrfy_pgset_get(pgset, i, &p)) != 0) 00792 goto err; 00793 if (p == 0) { 00794 EPRINT((dbp->dbenv, "Unreferenced page %lu", i)); 00795 /* isbad = 1; */ 00796 /* XXX: this is a db bug */ 00797 if (pip->type != P_LRECNO && pip->type != P_LDUP) 00798 isbad = 1; 00799 } 00800 00801 if (F_ISSET(pip, VRFY_IS_ALLZEROES)) { 00802 EPRINT((dbp->dbenv, "Totally zeroed page %lu", i)); 00803 isbad = 1; 00804 } 00805 if ((ret = CDB___db_vrfy_putpageinfo(vdp, pip)) != 0) 00806 goto err; 00807 pip = NULL; 00808 } 00809 00810 err: if (pip != NULL) 00811 (void)CDB___db_vrfy_putpageinfo(vdp, pip); 00812 00813 return ((isbad == 1 && ret == 0) ? DB_VERIFY_BAD : ret); 00814 } 00815 00816 /* 00817 * __db_is_valid_pagetype 00818 */ 00819 static int 00820 __db_is_valid_pagetype(type) 00821 u_int32_t type; 00822 { 00823 switch (type) { 00824 case P_INVALID: /* Order matches ordinal value. */ 00825 case P_HASH: 00826 case P_IBTREE: 00827 case P_IRECNO: 00828 case P_LBTREE: 00829 case P_LRECNO: 00830 case P_OVERFLOW: 00831 case P_HASHMETA: 00832 case P_BTREEMETA: 00833 case P_QAMMETA: 00834 case P_QAMDATA: 00835 case P_LDUP: 00836 return (1); 00837 } 00838 return (0); 00839 } 00840 00841 /* 00842 * __db_is_valid_magicno 00843 */ 00844 static int 00845 __db_is_valid_magicno(magic, typep) 00846 u_int32_t magic; 00847 DBTYPE *typep; 00848 { 00849 switch (magic) { 00850 case DB_BTREEMAGIC: 00851 *typep = DB_BTREE; 00852 return (1); 00853 case DB_HASHMAGIC: 00854 *typep = DB_HASH; 00855 return (1); 00856 case DB_QAMMAGIC: 00857 *typep = DB_QUEUE; 00858 return (1); 00859 } 00860 *typep = DB_UNKNOWN; 00861 return (0); 00862 } 00863 00864 /* 00865 * __db_vrfy_common -- 00866 * Verify info common to all page types. 00867 */ 00868 static int 00869 __db_vrfy_common(dbp, vdp, h, pgno, flags) 00870 DB *dbp; 00871 VRFY_DBINFO *vdp; 00872 PAGE *h; 00873 db_pgno_t pgno; 00874 u_int32_t flags; 00875 { 00876 VRFY_PAGEINFO *pip; 00877 int ret, t_ret; 00878 u_int8_t *p; 00879 00880 if ((ret = CDB___db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0) 00881 return (ret); 00882 00883 pip->pgno = pgno; 00884 F_CLR(pip, VRFY_IS_ALLZEROES); 00885 00886 /* 00887 * Hash expands the table by leaving some pages between the 00888 * old last and the new last totally zeroed. Its pgin function 00889 * should fix things, but we might not be using that (e.g. if 00890 * we're a subdatabase). 00891 */ 00892 if (pgno != 0 && PGNO(h) == 0) { 00893 for (p = (u_int8_t *)h; p < (u_int8_t *)h + dbp->pgsize; p++) 00894 if (*p != 0) { 00895 EPRINT((dbp->dbenv, 00896 "Hash page %lu should be zeroed and is not", 00897 pgno)); 00898 ret = DB_VERIFY_BAD; 00899 goto err; 00900 } 00901 /* 00902 * It's totally zeroed; mark it as a hash, and we'll 00903 * check that that makes sense structurally later. 00904 */ 00905 pip->type = P_HASH; 00906 F_SET(pip, VRFY_IS_ALLZEROES); 00907 ret = 0; 00908 goto err; /* well, not really an err. */ 00909 } 00910 00911 if (PGNO(h) != pgno) { 00912 EPRINT((dbp->dbenv, 00913 "Bad page number: %lu should be %lu", h->pgno, pgno)); 00914 ret = DB_VERIFY_BAD; 00915 } 00916 00917 if (!__db_is_valid_pagetype(h->type)) { 00918 EPRINT((dbp->dbenv, "Bad page type: %lu", h->type)); 00919 ret = DB_VERIFY_BAD; 00920 } 00921 pip->type = h->type; 00922 00923 err: if ((t_ret = CDB___db_vrfy_putpageinfo(vdp, pip)) != 0 && ret == 0) 00924 ret = t_ret; 00925 00926 return (ret); 00927 } 00928 00929 /* 00930 * __db_vrfy_invalid -- 00931 * Verify P_INVALID page. 00932 * (Yes, there's not much to do here.) 00933 */ 00934 static int 00935 __db_vrfy_invalid(dbp, vdp, h, pgno, flags) 00936 DB *dbp; 00937 VRFY_DBINFO *vdp; 00938 PAGE *h; 00939 db_pgno_t pgno; 00940 u_int32_t flags; 00941 { 00942 VRFY_PAGEINFO *pip; 00943 int ret, t_ret; 00944 00945 if ((ret = CDB___db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0) 00946 return (ret); 00947 pip->next_pgno = pip->prev_pgno = 0; 00948 00949 if (!IS_VALID_PGNO(NEXT_PGNO(h))) { 00950 EPRINT((dbp->dbenv, 00951 "Invalid next_pgno %lu on page %lu", NEXT_PGNO(h), pgno)); 00952 ret = DB_VERIFY_BAD; 00953 } else 00954 pip->next_pgno = NEXT_PGNO(h); 00955 00956 if ((t_ret = CDB___db_vrfy_putpageinfo(vdp, pip)) != 0 && ret == 0) 00957 ret = t_ret; 00958 return (ret); 00959 } 00960 00961 /* 00962 * CDB___db_vrfy_datapage -- 00963 * Verify elements common to data pages (P_HASH, P_LBTREE, 00964 * P_IBTREE, P_IRECNO, P_LRECNO, P_OVERFLOW, P_DUPLICATE)--i.e., 00965 * those defined in the PAGE structure. 00966 * 00967 * Called from each of the per-page routines, after the 00968 * all-page-type-common elements of pip have been verified and filled 00969 * in. 00970 * 00971 * PUBLIC: int CDB___db_vrfy_datapage 00972 * PUBLIC: __P((DB *, VRFY_DBINFO *, PAGE *, db_pgno_t, u_int32_t)); 00973 */ 00974 int 00975 CDB___db_vrfy_datapage(dbp, vdp, h, pgno, flags) 00976 DB *dbp; 00977 VRFY_DBINFO *vdp; 00978 PAGE *h; 00979 db_pgno_t pgno; 00980 u_int32_t flags; 00981 { 00982 VRFY_PAGEINFO *pip; 00983 int isbad, ret, t_ret; 00984 00985 if ((ret = CDB___db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0) 00986 return (ret); 00987 isbad = 0; 00988 00989 /* 00990 * prev_pgno and next_pgno: store for inter-page checks, 00991 * verify that they point to actual pages and not to self. 00992 * 00993 * !!! 00994 * Internal btree pages do not maintain these fields (indeed, 00995 * they overload them). Skip. 00996 */ 00997 if (TYPE(h) != P_IBTREE && TYPE(h) != P_IRECNO) { 00998 if (!IS_VALID_PGNO(PREV_PGNO(h)) || PREV_PGNO(h) == pip->pgno) { 00999 isbad = 1; 01000 EPRINT((dbp->dbenv, "Page %lu: Invalid prev_pgno %lu", 01001 pip->pgno, PREV_PGNO(h))); 01002 } 01003 if (!IS_VALID_PGNO(NEXT_PGNO(h)) || NEXT_PGNO(h) == pip->pgno) { 01004 isbad = 1; 01005 EPRINT((dbp->dbenv, "Page %lu: Invalid next_pgno %lu", 01006 pip->pgno, NEXT_PGNO(h))); 01007 } 01008 pip->prev_pgno = PREV_PGNO(h); 01009 pip->next_pgno = NEXT_PGNO(h); 01010 } 01011 01012 /* 01013 * Verify the number of entries on the page. 01014 * There is no good way to determine if this is accurate; the 01015 * best we can do is verify that it's not more than can, in theory, 01016 * fit on the page. Then, we make sure there are at least 01017 * this many valid elements in inp[], and hope that this catches 01018 * most cases. 01019 */ 01020 if (TYPE(h) != P_OVERFLOW) { 01021 if (BKEYDATA_PSIZE(0) * NUM_ENT(h) > dbp->pgsize) { 01022 isbad = 1; 01023 EPRINT((dbp->dbenv, 01024 "Page %lu: Too many entries: %lu", 01025 pgno, NUM_ENT(h))); 01026 } 01027 pip->entries = NUM_ENT(h); 01028 } 01029 01030 /* 01031 * btree level. Should be zero unless we're a btree; 01032 * if we are a btree, should be between LEAFLEVEL and MAXBTREELEVEL, 01033 * and we need to save it off. 01034 */ 01035 switch (TYPE(h)) { 01036 case P_IBTREE: 01037 case P_IRECNO: 01038 if (LEVEL(h) < LEAFLEVEL + 1 || LEVEL(h) > MAXBTREELEVEL) { 01039 isbad = 1; 01040 EPRINT((dbp->dbenv, "Bad btree level %lu on page %lu", 01041 LEVEL(h), pgno)); 01042 } 01043 pip->bt_level = LEVEL(h); 01044 break; 01045 case P_LBTREE: 01046 case P_LDUP: 01047 case P_LRECNO: 01048 if (LEVEL(h) != LEAFLEVEL) { 01049 isbad = 1; 01050 EPRINT((dbp->dbenv, 01051 "Btree leaf page %lu has incorrect level %lu", 01052 pgno, LEVEL(h))); 01053 } 01054 break; 01055 default: 01056 if (LEVEL(h) != 0) { 01057 isbad = 1; 01058 EPRINT((dbp->dbenv, 01059 "Nonzero level %lu in non-btree database page %lu", 01060 LEVEL(h), pgno)); 01061 } 01062 break; 01063 } 01064 01065 /* 01066 * Even though inp[] occurs in all PAGEs, we look at it in the 01067 * access-method-specific code, since btree and hash treat 01068 * item lengths very differently, and one of the most important 01069 * things we want to verify is that the data--as specified 01070 * by offset and length--cover the right part of the page 01071 * without overlaps, gaps, or violations of the page boundary. 01072 */ 01073 if ((t_ret = CDB___db_vrfy_putpageinfo(vdp, pip)) != 0 && ret == 0) 01074 ret = t_ret; 01075 01076 return ((ret == 0 && isbad == 1) ? DB_VERIFY_BAD : ret); 01077 } 01078 01079 /* 01080 * CDB___db_vrfy_meta-- 01081 * Verify the access-method common parts of a meta page, using 01082 * normal mpool routines. 01083 * 01084 * PUBLIC: int CDB___db_vrfy_meta 01085 * PUBLIC: __P((DB *, VRFY_DBINFO *, DBMETA *, db_pgno_t, u_int32_t)); 01086 */ 01087 int 01088 CDB___db_vrfy_meta(dbp, vdp, meta, pgno, flags) 01089 DB *dbp; 01090 VRFY_DBINFO *vdp; 01091 DBMETA *meta; 01092 db_pgno_t pgno; 01093 u_int32_t flags; 01094 { 01095 DBTYPE dbtype, magtype; 01096 VRFY_PAGEINFO *pip; 01097 int isbad, ret, t_ret; 01098 01099 isbad = 0; 01100 if ((ret = CDB___db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0) 01101 return (ret); 01102 01103 /* type plausible for a meta page */ 01104 switch (meta->type) { 01105 case P_BTREEMETA: 01106 dbtype = DB_BTREE; 01107 break; 01108 case P_HASHMETA: 01109 dbtype = DB_HASH; 01110 break; 01111 case P_QAMMETA: 01112 dbtype = DB_QUEUE; 01113 break; 01114 default: 01115 /* The verifier should never let us get here. */ 01116 DB_ASSERT(0); 01117 ret = EINVAL; 01118 goto err; 01119 } 01120 01121 /* magic number valid */ 01122 if (!__db_is_valid_magicno(meta->magic, &magtype)) { 01123 isbad = 1; 01124 EPRINT((dbp->dbenv, "Magic number invalid on page %lu", pgno)); 01125 } 01126 if (magtype != dbtype) { 01127 isbad = 1; 01128 EPRINT((dbp->dbenv, 01129 "Magic number does not match type of page %lu", pgno)); 01130 } 01131 01132 /* version */ 01133 if ((dbtype == DB_BTREE && meta->version != DB_BTREEVERSION) || 01134 (dbtype == DB_HASH && meta->version != DB_HASHVERSION) || 01135 (dbtype == DB_QUEUE && meta->version != DB_QAMVERSION)) { 01136 isbad = 1; 01137 EPRINT((dbp->dbenv, "%s%s", "Old of incorrect DB ", 01138 "version; extraneous errors may result")); 01139 } 01140 01141 /* pagesize */ 01142 if (meta->pagesize != dbp->pgsize) { 01143 isbad = 1; 01144 EPRINT((dbp->dbenv, 01145 "Invalid pagesize %lu on page %lu", meta->pagesize, pgno)); 01146 } 01147 01148 /* free list */ 01149 /* Can correctly be PGNO_INVALID--that's just the end of the list. */ 01150 if (meta->free != PGNO_INVALID && IS_VALID_PGNO(meta->free)) 01151 pip->free = meta->free; 01152 else if (!IS_VALID_PGNO(meta->free)) { 01153 isbad = 1; 01154 EPRINT((dbp->dbenv, 01155 "Nonsensical free list pgno %lu on page %lu", 01156 meta->free, pgno)); 01157 } 01158 01159 err: if ((t_ret = CDB___db_vrfy_putpageinfo(vdp, pip)) != 0 && ret == 0) 01160 ret = t_ret; 01161 01162 return ((ret == 0 && isbad == 1) ? DB_VERIFY_BAD : ret); 01163 } 01164 01165 /* 01166 * __db_vrfy_freelist -- 01167 * Walk free list, checking off pages and verifying absence of 01168 * loops. 01169 */ 01170 static int 01171 __db_vrfy_freelist(dbp, vdp, meta, flags) 01172 DB *dbp; 01173 VRFY_DBINFO *vdp; 01174 db_pgno_t meta; 01175 u_int32_t flags; 01176 { 01177 DB *pgset; 01178 VRFY_PAGEINFO *pip; 01179 db_pgno_t pgno; 01180 int p, ret, t_ret; 01181 01182 pgset = vdp->pgset; 01183 DB_ASSERT(pgset != NULL); 01184 01185 if ((ret = CDB___db_vrfy_getpageinfo(vdp, meta, &pip)) != 0) 01186 return (ret); 01187 for (pgno = pip->free; pgno != PGNO_INVALID; pgno = pip->next_pgno) { 01188 if ((ret = CDB___db_vrfy_putpageinfo(vdp, pip)) != 0) 01189 return (ret); 01190 01191 /* This shouldn't happen, but just in case. */ 01192 if (!IS_VALID_PGNO(pgno)) { 01193 EPRINT((dbp->dbenv, 01194 "Invalid next_pgno on free list page %lu", pgno)); 01195 return (DB_VERIFY_BAD); 01196 } 01197 01198 /* Detect cycles. */ 01199 if ((ret = CDB___db_vrfy_pgset_get(pgset, pgno, &p)) != 0) 01200 return (ret); 01201 if (p != 0) { 01202 EPRINT((dbp->dbenv, 01203 "Page %lu encountered a second time on free list", 01204 pgno)); 01205 return (DB_VERIFY_BAD); 01206 } 01207 if ((ret = CDB___db_vrfy_pgset_inc(pgset, pgno)) != 0) 01208 return (ret); 01209 01210 if ((ret = CDB___db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0) 01211 return (ret); 01212 01213 if (pip->type != P_INVALID) { 01214 EPRINT((dbp->dbenv, "Non-invalid page %lu on free list", 01215 pgno, pip->type)); 01216 ret = DB_VERIFY_BAD; /* unsafe to continue */ 01217 break; 01218 } 01219 } 01220 01221 if ((t_ret = CDB___db_vrfy_putpageinfo(vdp, pip)) != 0) 01222 ret = t_ret; 01223 return (ret); 01224 } 01225 01226 /* 01227 * __db_vrfy_subdbs -- 01228 * Walk the known-safe master database of subdbs with a cursor, 01229 * verifying the structure of each subdatabase we encounter. 01230 */ 01231 static int 01232 __db_vrfy_subdbs(dbp, vdp, dbname, flags) 01233 DB *dbp; 01234 VRFY_DBINFO *vdp; 01235 char *dbname; 01236 u_int32_t flags; 01237 { 01238 DB *mdbp; 01239 DBC *dbc; 01240 DBT key, data; 01241 VRFY_PAGEINFO *pip; 01242 db_pgno_t meta_pgno; 01243 int ret, t_ret, isbad; 01244 u_int8_t type; 01245 01246 isbad = 0; 01247 dbc = NULL; 01248 01249 if ((ret = CDB___db_master_open(dbp, dbname, DB_RDONLY, 0, &mdbp)) != 0) 01250 return (ret); 01251 01252 if ((ret = 01253 CDB___db_icursor(mdbp, NULL, DB_BTREE, PGNO_INVALID, 0, &dbc)) != 0) 01254 goto err; 01255 01256 memset(&key, 0, sizeof(key)); 01257 memset(&data, 0, sizeof(data)); 01258 while ((ret = dbc->c_get(dbc, &key, &data, DB_NEXT)) == 0) { 01259 if (data.size != sizeof(db_pgno_t)) { 01260 EPRINT((dbp->dbenv, "Database entry of invalid size")); 01261 isbad = 1; 01262 goto err; 01263 } 01264 memcpy(&meta_pgno, data.data, data.size); 01265 /* 01266 * Subdatabase meta pgnos are stored in network byte 01267 * order for cross-endian compatibility. Swap if appropriate. 01268 */ 01269 DB_NTOHL(&meta_pgno); 01270 if (meta_pgno == PGNO_INVALID || meta_pgno > vdp->last_pgno) { 01271 EPRINT((dbp->dbenv, 01272 "Database entry references invalid page %lu", 01273 meta_pgno)); 01274 isbad = 1; 01275 goto err; 01276 } 01277 if ((ret = CDB___db_vrfy_getpageinfo(vdp, meta_pgno, &pip)) != 0) 01278 goto err; 01279 type = pip->type; 01280 if ((ret = CDB___db_vrfy_putpageinfo(vdp, pip)) != 0) 01281 goto err; 01282 switch (type) { 01283 case P_BTREEMETA: 01284 if ((ret = CDB___bam_vrfy_structure( 01285 dbp, vdp, meta_pgno, flags)) != 0) { 01286 if (ret == DB_VERIFY_BAD) 01287 isbad = 1; 01288 else 01289 goto err; 01290 } 01291 break; 01292 case P_HASHMETA: 01293 if ((ret = CDB___ham_vrfy_structure( 01294 dbp, vdp, meta_pgno, flags)) != 0) { 01295 if (ret == DB_VERIFY_BAD) 01296 isbad = 1; 01297 else 01298 goto err; 01299 } 01300 break; 01301 case P_QAMMETA: 01302 default: 01303 EPRINT((dbp->dbenv, 01304 "Database entry references page %lu of invalid type %lu", 01305 meta_pgno, type)); 01306 ret = DB_VERIFY_BAD; 01307 goto err; 01308 /* NOTREACHED */ 01309 } 01310 } 01311 01312 if (ret == DB_NOTFOUND) 01313 ret = 0; 01314 01315 err: if (dbc != NULL && (t_ret = CDB___db_c_close(dbc)) != 0 && ret == 0) 01316 ret = t_ret; 01317 01318 if ((t_ret = mdbp->close(mdbp, 0)) != 0 && ret == 0) 01319 ret = t_ret; 01320 01321 return ((ret == 0 && isbad == 1) ? DB_VERIFY_BAD : ret); 01322 } 01323 01324 /* 01325 * __db_vrfy_orderchkonly -- 01326 * Do an sort-order/hashing check on a known-otherwise-good subdb. 01327 */ 01328 static int 01329 __db_vrfy_orderchkonly(dbp, vdp, name, subdb, flags) 01330 DB *dbp; 01331 VRFY_DBINFO *vdp; 01332 const char *name, *subdb; 01333 u_int32_t flags; 01334 { 01335 BTMETA *btmeta; 01336 DB *mdbp, *pgset; 01337 DBC *pgsc; 01338 DBT key, data; 01339 HASH *h_internal; 01340 HMETA *hmeta; 01341 PAGE *h, *currpg; 01342 db_pgno_t meta_pgno, p, pgno; 01343 u_int32_t bucket; 01344 int t_ret, ret; 01345 01346 currpg = h = NULL; 01347 pgsc = NULL; 01348 pgset = NULL; 01349 01350 LF_CLR(DB_NOORDERCHK); 01351 01352 /* Open the master database and get the meta_pgno for the subdb. */ 01353 if ((ret = CDB_db_create(&mdbp, NULL, 0)) != 0) 01354 return (ret); 01355 if ((ret = CDB___db_master_open(dbp, name, DB_RDONLY, 0, &mdbp)) != 0) 01356 goto err; 01357 01358 memset(&key, 0, sizeof(key)); 01359 key.data = (void *)subdb; 01360 memset(&data, 0, sizeof(data)); 01361 if ((ret = dbp->get(dbp, NULL, &key, &data, 0)) != 0) 01362 goto err; 01363 01364 if (data.size != sizeof(db_pgno_t)) { 01365 EPRINT((dbp->dbenv, "Database entry of invalid size")); 01366 ret = DB_VERIFY_BAD; 01367 goto err; 01368 } 01369 01370 memcpy(&meta_pgno, data.data, data.size); 01371 01372 if ((ret = CDB_memp_fget(dbp->mpf, &meta_pgno, 0, &h)) != 0) 01373 goto err; 01374 01375 if ((ret = CDB___db_vrfy_pgset(dbp->dbenv, dbp->pgsize, &pgset)) != 0) 01376 goto err; 01377 01378 switch (TYPE(h)) { 01379 case P_BTREEMETA: 01380 btmeta = (BTMETA *)h; 01381 if (F_ISSET(&btmeta->dbmeta, BTM_RECNO)) { 01382 /* Recnos have no order to check. */ 01383 ret = 0; 01384 goto err; 01385 } 01386 if ((ret = 01387 __db_meta2pgset(dbp, vdp, meta_pgno, flags, pgset)) != 0) 01388 goto err; 01389 if ((ret = pgset->cursor(pgset, NULL, &pgsc, 0)) != 0) 01390 goto err; 01391 while ((ret = CDB___db_vrfy_pgset_next(pgsc, &p)) == 0) { 01392 if ((ret = CDB_memp_fget(dbp->mpf, &p, 0, &currpg)) != 0) 01393 goto err; 01394 if ((ret = CDB___bam_vrfy_itemorder(dbp, 01395 NULL, currpg, p, NUM_ENT(currpg), 1, 01396 F_ISSET(&btmeta->dbmeta, BTM_DUP), flags)) != 0) 01397 goto err; 01398 if ((ret = CDB_memp_fput(dbp->mpf, currpg, 0)) != 0) 01399 goto err; 01400 currpg = NULL; 01401 } 01402 if ((ret = pgsc->c_close(pgsc)) != 0) 01403 goto err; 01404 break; 01405 case P_HASHMETA: 01406 hmeta = (HMETA *)h; 01407 h_internal = (HASH *)dbp->h_internal; 01408 /* 01409 * Make sure h_charkey is right. 01410 */ 01411 if (h_internal == NULL || h_internal->h_hash == NULL) { 01412 EPRINT((dbp->dbenv, 01413 "DB_ORDERCHKONLY requires that a hash function be set")); 01414 ret = DB_VERIFY_BAD; 01415 goto err; 01416 } 01417 if (hmeta->h_charkey != 01418 h_internal->h_hash(CHARKEY, sizeof(CHARKEY))) { 01419 EPRINT((dbp->dbenv, 01420 "Incorrect hash function for database")); 01421 ret = DB_VERIFY_BAD; 01422 goto err; 01423 } 01424 01425 /* 01426 * Foreach bucket, verify hashing on each page in the 01427 * corresponding chain of pages. 01428 */ 01429 for (bucket = 0; bucket <= hmeta->max_bucket; bucket++) { 01430 pgno = hmeta->spares[CDB___db_log2(bucket + 1)]; 01431 while (pgno != PGNO_INVALID) { 01432 if ((ret = CDB_memp_fget(dbp->mpf, 01433 &pgno, 0, &currpg)) != 0) 01434 goto err; 01435 if ((ret = CDB___ham_vrfy_hashing(dbp, 01436 NUM_ENT(currpg),hmeta, bucket, pgno, 01437 flags, h_internal->h_hash)) != 0) 01438 goto err; 01439 pgno = NEXT_PGNO(currpg); 01440 if ((ret = CDB_memp_fput(dbp->mpf, currpg, 0)) != 0) 01441 goto err; 01442 currpg = NULL; 01443 } 01444 } 01445 break; 01446 default: 01447 EPRINT((dbp->dbenv, "Database meta page %lu of bad type %lu", 01448 meta_pgno, TYPE(h))); 01449 ret = DB_VERIFY_BAD; 01450 break; 01451 } 01452 01453 err: if (pgsc != NULL) 01454 (void)pgsc->c_close(pgsc); 01455 if (pgset != NULL) 01456 (void)pgset->close(pgset, 0); 01457 if (h != NULL && (t_ret = CDB_memp_fput(dbp->mpf, h, 0)) != 0) 01458 ret = t_ret; 01459 if (currpg != NULL && (t_ret = CDB_memp_fput(dbp->mpf, currpg, 0)) != 0) 01460 ret = t_ret; 01461 if ((t_ret = mdbp->close(mdbp, 0)) != 0) 01462 ret = t_ret; 01463 return (ret); 01464 } 01465 01466 /* 01467 * CDB___db_salvage -- 01468 * Walk through a page, salvaging all likely or plausible (w/ 01469 * DB_AGGRESSIVE) key/data pairs. 01470 * 01471 * PUBLIC: int CDB___db_salvage __P((DB *, VRFY_DBINFO *, db_pgno_t, PAGE *, 01472 * PUBLIC: void *, int (*)(void *, const void *), u_int32_t)); 01473 */ 01474 int 01475 CDB___db_salvage(dbp, vdp, pgno, h, handle, callback, flags) 01476 DB *dbp; 01477 VRFY_DBINFO *vdp; 01478 db_pgno_t pgno; 01479 PAGE *h; 01480 void *handle; 01481 int (*callback) __P((void *, const void *)); 01482 u_int32_t flags; 01483 { 01484 DB_ASSERT(LF_ISSET(DB_SALVAGE)); 01485 01486 /* If we got this page in the subdb pass, we can safely skip it. */ 01487 if (CDB___db_salvage_isdone(vdp, pgno)) 01488 return (0); 01489 01490 switch (TYPE(h)) { 01491 case P_HASH: 01492 return (CDB___ham_salvage(dbp, 01493 vdp, pgno, h, handle, callback, flags)); 01494 /* NOTREACHED */ 01495 case P_LBTREE: 01496 return (CDB___bam_salvage(dbp, 01497 vdp, pgno, P_LBTREE, h, handle, callback, NULL, flags)); 01498 /* NOTREACHED */ 01499 case P_LDUP: 01500 return (CDB___db_salvage_markneeded(vdp, pgno, SALVAGE_LDUP)); 01501 /* NOTREACHED */ 01502 case P_OVERFLOW: 01503 return (CDB___db_salvage_markneeded(vdp, pgno, SALVAGE_OVERFLOW)); 01504 /* NOTREACHED */ 01505 case P_LRECNO: 01506 /* 01507 * Recnos are tricky -- they may represent dup pages, or 01508 * they may be subdatabase/regular database pages in their 01509 * own right. If the former, they need to be printed with a 01510 * key, preferably when we hit the corresponding datum in 01511 * a btree/hash page. If the latter, there is no key. 01512 * 01513 * If a database is sufficiently frotzed, we're not going 01514 * to be able to get this right, so we best-guess: just 01515 * mark it needed now, and if we're really a normal recno 01516 * database page, the "unknowns" pass will pick us up. 01517 */ 01518 return (CDB___db_salvage_markneeded(vdp, pgno, SALVAGE_LRECNO)); 01519 /* NOTREACHED */ 01520 case P_IBTREE: 01521 case P_INVALID: 01522 case P_IRECNO: 01523 case __P_DUPLICATE: 01524 default: 01525 /* XXX: Should we be more aggressive here? */ 01526 break; 01527 } 01528 return (0); 01529 } 01530 01531 /* 01532 * __db_salvage_unknowns -- 01533 * Walk through the salvager database, printing with key "UNKNOWN" 01534 * any pages we haven't dealt with. 01535 */ 01536 static int 01537 __db_salvage_unknowns(dbp, vdp, handle, callback, flags) 01538 DB *dbp; 01539 VRFY_DBINFO *vdp; 01540 void *handle; 01541 int (*callback) __P((void *, const void *)); 01542 u_int32_t flags; 01543 { 01544 DBT unkdbt, key, *dbt; 01545 PAGE *h; 01546 db_pgno_t pgno; 01547 u_int32_t pgtype; 01548 int ret, err_ret; 01549 void *ovflbuf; 01550 01551 memset(&unkdbt, 0, sizeof(DBT)); 01552 unkdbt.size = strlen("UNKNOWN") + 1; 01553 unkdbt.data = "UNKNOWN"; 01554 01555 if ((ret = CDB___os_malloc(dbp->dbenv, dbp->pgsize, 0, &ovflbuf)) != 0) 01556 return (ret); 01557 01558 err_ret = 0; 01559 while ((ret = CDB___db_salvage_getnext(vdp, &pgno, &pgtype)) == 0) { 01560 dbt = NULL; 01561 01562 if ((ret = CDB_memp_fget(dbp->mpf, &pgno, 0, &h)) != 0) { 01563 err_ret = ret; 01564 continue; 01565 } 01566 01567 switch (pgtype) { 01568 case SALVAGE_LDUP: 01569 case SALVAGE_LRECNODUP: 01570 dbt = &unkdbt; 01571 /* FALLTHROUGH */ 01572 case SALVAGE_LBTREE: 01573 case SALVAGE_LRECNO: 01574 if ((ret = CDB___bam_salvage(dbp, vdp, pgno, pgtype, 01575 h, handle, callback, dbt, flags)) != 0) 01576 err_ret = ret; 01577 break; 01578 case SALVAGE_OVERFLOW: 01579 /* 01580 * XXX: 01581 * This may generate multiple "UNKNOWN" keys in 01582 * a database with no dups. What to do? 01583 */ 01584 if ((ret = CDB___db_safe_goff(dbp, 01585 vdp, pgno, &key, &ovflbuf, flags)) != 0) { 01586 err_ret = ret; 01587 continue; 01588 } 01589 if ((ret = CDB___db_prdbt(&key, 01590 0, " ", handle, callback, 0, NULL)) != 0) { 01591 err_ret = ret; 01592 continue; 01593 } 01594 if ((ret = CDB___db_prdbt(&unkdbt, 01595 0, " ", handle, callback, 0, NULL)) != 0) 01596 err_ret = ret; 01597 break; 01598 case SALVAGE_HASH: 01599 if ((ret = CDB___ham_salvage( 01600 dbp, vdp, pgno, h, handle, callback, flags)) != 0) 01601 err_ret = ret; 01602 break; 01603 case SALVAGE_INVALID: 01604 case SALVAGE_IGNORE: 01605 default: 01606 /* 01607 * Shouldn't happen, but if it does, just do what the 01608 * nice man says. 01609 */ 01610 DB_ASSERT(0); 01611 break; 01612 } 01613 if ((ret = CDB_memp_fput(dbp->mpf, h, 0)) != 0) 01614 err_ret = ret; 01615 } 01616 01617 CDB___os_free(ovflbuf, 0); 01618 01619 if (err_ret != 0 && ret == 0) 01620 ret = err_ret; 01621 01622 return (ret == DB_NOTFOUND ? 0 : ret); 01623 } 01624 01625 /* 01626 * Offset of the ith inp array entry, which we can compare to the offset 01627 * the entry stores. 01628 */ 01629 #define INP_OFFSET(h, i) \ 01630 ((db_indx_t)((u_int8_t *)(h)->inp + (i) - (u_int8_t *)(h))) 01631 01632 /* 01633 * CDB___db_vrfy_inpitem -- 01634 * Verify that a single entry in the inp array is sane, and update 01635 * the high water mark and current item offset. (The former of these is 01636 * used for state information between calls, and is required; it must 01637 * be initialized to the pagesize before the first call.) 01638 * 01639 * Returns DB_VERIFY_FATAL if inp has collided with the data, 01640 * since verification can't continue from there; returns DB_VERIFY_BAD 01641 * if anything else is wrong. 01642 * 01643 * PUBLIC: int CDB___db_vrfy_inpitem __P((DB *, PAGE *, 01644 * PUBLIC: db_pgno_t, u_int32_t, int, u_int32_t, u_int32_t *, u_int32_t *)); 01645 */ 01646 int 01647 CDB___db_vrfy_inpitem(dbp, h, pgno, i, is_btree, flags, himarkp, offsetp) 01648 DB *dbp; 01649 PAGE *h; 01650 db_pgno_t pgno; 01651 u_int32_t i; 01652 int is_btree; 01653 u_int32_t flags, *himarkp, *offsetp; 01654 { 01655 BKEYDATA *bk; 01656 db_indx_t offset, len; 01657 01658 DB_ASSERT(himarkp != NULL); 01659 01660 /* 01661 * Check that the inp array, which grows from the beginning of the 01662 * page forward, has not collided with the data, which grow from the 01663 * end of the page backward. 01664 */ 01665 if ((u_int8_t *)h->inp + i >= (u_int8_t *)h + *himarkp) { 01666 /* We've collided with the data. We need to bail. */ 01667 EPRINT((dbp->dbenv, 01668 "Page %lu entries listing %lu overlaps data", pgno, i)); 01669 return (DB_VERIFY_FATAL); 01670 } 01671 01672 offset = h->inp[i]; 01673 01674 /* 01675 * Check that the item offset is reasonable: it points somewhere 01676 * after the inp array and before the end of the page. 01677 */ 01678 if (offset <= INP_OFFSET(h, i) || offset > dbp->pgsize) { 01679 EPRINT((dbp->dbenv, 01680 "Bad offset %lu at page %lu index %lu", offset, pgno, i)); 01681 return (DB_VERIFY_BAD); 01682 } 01683 01684 /* Update the high-water mark (what HOFFSET should be) */ 01685 if (offset < *himarkp) 01686 *himarkp = offset; 01687 01688 if (is_btree) { 01689 /* 01690 * Check that the item length remains on-page. 01691 */ 01692 bk = GET_BKEYDATA(h, i); 01693 len = B_TYPE(bk->type) == B_KEYDATA ? bk->len : BOVERFLOW_SIZE; 01694 if ((size_t)(offset + len) > dbp->pgsize) { 01695 EPRINT((dbp->dbenv, 01696 "Item %lu on page %lu extends past page boundary", 01697 i, pgno)); 01698 return (DB_VERIFY_BAD); 01699 } 01700 } 01701 01702 if (offsetp != NULL) 01703 *offsetp = offset; 01704 return (0); 01705 } 01706 01707 /* 01708 * CDB___db_vrfy_duptype-- 01709 * Given a page number and a set of flags to CDB___bam_vrfy_subtree, 01710 * verify that the dup tree type is correct--i.e., it's a recno 01711 * if DUPSORT is not set and a btree if it is. 01712 * 01713 * PUBLIC: int CDB___db_vrfy_duptype 01714 * PUBLIC: __P((DB *, VRFY_DBINFO *, db_pgno_t, u_int32_t)); 01715 */ 01716 int 01717 CDB___db_vrfy_duptype(dbp, vdp, pgno, flags) 01718 DB *dbp; 01719 VRFY_DBINFO *vdp; 01720 db_pgno_t pgno; 01721 u_int32_t flags; 01722 { 01723 VRFY_PAGEINFO *pip; 01724 int ret, isbad; 01725 01726 isbad = 0; 01727 01728 if ((ret = CDB___db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0) 01729 return (ret); 01730 01731 switch (pip->type) { 01732 case P_IBTREE: 01733 case P_LDUP: 01734 if (!LF_ISSET(ST_DUPSORT)) { 01735 EPRINT((dbp->dbenv, 01736 "Sorted duplicate set at page %lu in unsorted-dup database", 01737 pgno)); 01738 isbad = 1; 01739 } 01740 break; 01741 case P_IRECNO: 01742 case P_LRECNO: 01743 if (LF_ISSET(ST_DUPSORT)) { 01744 EPRINT((dbp->dbenv, 01745 "Unsorted duplicate set at page %lu in sorted-dup database", 01746 pgno)); 01747 isbad = 1; 01748 } 01749 break; 01750 default: 01751 EPRINT((dbp->dbenv, "Duplicate page %lu of inappropriate type %lu", 01752 pgno, pip->type)); 01753 isbad = 1; 01754 break; 01755 } 01756 01757 if ((ret = CDB___db_vrfy_putpageinfo(vdp, pip)) != 0) 01758 return (ret); 01759 return (isbad == 1 ? DB_VERIFY_BAD : 0); 01760 } 01761 01762 /* 01763 * CDB___db_salvage_duptree -- 01764 * Attempt to salvage a given duplicate tree, given its alleged root. 01765 * 01766 * The key that corresponds to this dup set has been passed to us 01767 * in DBT *key. Because data items follow keys, though, it has been 01768 * printed once already. 01769 * 01770 * The basic idea here is that pgno ought to be a P_LDUP, a P_LRECNO, a 01771 * P_IBTREE, or a P_IRECNO. If it's an internal page, use the verifier 01772 * functions to make sure it's safe; if it's not, we simply bail and the 01773 * data will have to be printed with no key later on. if it is safe, 01774 * recurse on each of its children. 01775 * 01776 * Whether or not it's safe, if it's a leaf page, CDB___bam_salvage it. 01777 * 01778 * At all times, use the DB hanging off vdp to mark and check what we've 01779 * done, so each page gets printed exactly once and we don't get caught 01780 * in any cycles. 01781 * 01782 * PUBLIC: int CDB___db_salvage_duptree __P((DB *, VRFY_DBINFO *, db_pgno_t, 01783 * PUBLIC: DBT *, void *, int (*)(void *, const void *), u_int32_t)); 01784 */ 01785 int 01786 CDB___db_salvage_duptree(dbp, vdp, pgno, key, handle, callback, flags) 01787 DB *dbp; 01788 VRFY_DBINFO *vdp; 01789 db_pgno_t pgno; 01790 DBT *key; 01791 void *handle; 01792 int (*callback) __P((void *, const void *)); 01793 u_int32_t flags; 01794 { 01795 PAGE *h; 01796 int ret, t_ret; 01797 01798 if (pgno == PGNO_INVALID || !IS_VALID_PGNO(pgno)) 01799 return (DB_VERIFY_BAD); 01800 01801 /* We have a plausible page. Try it. */ 01802 if ((ret = CDB_memp_fget(dbp->mpf, &pgno, 0, &h)) != 0) 01803 return (ret); 01804 01805 switch (TYPE(h)) { 01806 case P_IBTREE: 01807 case P_IRECNO: 01808 if ((ret = __db_vrfy_common(dbp, vdp, h, pgno, flags)) != 0) 01809 goto err; 01810 if ((ret = CDB___bam_vrfy(dbp, 01811 vdp, h, pgno, flags | DB_NOORDERCHK)) != 0 || 01812 (ret = CDB___db_salvage_markdone(vdp, pgno)) != 0) 01813 goto err; 01814 /* 01815 * We have a known-healthy internal page. Walk it. 01816 */ 01817 if ((ret = CDB___bam_salvage_walkdupint(dbp, vdp, h, key, 01818 handle, callback, flags)) != 0) 01819 goto err; 01820 break; 01821 case P_LRECNO: 01822 case P_LDUP: 01823 if ((ret = CDB___bam_salvage(dbp, 01824 vdp, pgno, TYPE(h), h, handle, callback, key, flags)) != 0) 01825 goto err; 01826 break; 01827 default: 01828 ret = DB_VERIFY_BAD; 01829 goto err; 01830 /* NOTREACHED */ 01831 } 01832 01833 err: if ((t_ret = CDB_memp_fput(dbp->mpf, h, 0)) != 0 && ret == 0) 01834 ret = t_ret; 01835 return (ret); 01836 } 01837 01838 /* 01839 * __db_salvage_subdbs -- 01840 * Check and see if this database has subdbs; if so, try to salvage 01841 * them independently. 01842 */ 01843 static int 01844 __db_salvage_subdbs(dbp, vdp, handle, callback, flags, hassubsp) 01845 DB *dbp; 01846 VRFY_DBINFO *vdp; 01847 void *handle; 01848 int (*callback) __P((void *, const void *)); 01849 u_int32_t flags; 01850 int *hassubsp; 01851 { 01852 BTMETA *btmeta; 01853 DB *pgset; 01854 DBC *pgsc; 01855 PAGE *h; 01856 db_pgno_t p, meta_pgno; 01857 int ret, err_ret; 01858 01859 err_ret = 0; 01860 pgsc = NULL; 01861 pgset = NULL; 01862 01863 meta_pgno = PGNO_BASE_MD; 01864 if ((ret = CDB_memp_fget(dbp->mpf, &meta_pgno, 0, &h)) != 0) 01865 return (ret); 01866 01867 if (TYPE(h) == P_BTREEMETA) 01868 btmeta = (BTMETA *)h; 01869 else { 01870 /* Not a btree metadata, ergo no subdbs, so just return. */ 01871 ret = 0; 01872 goto err; 01873 } 01874 01875 /* If it's not a safe page, bail on the attempt. */ 01876 if ((ret = __db_vrfy_common(dbp, vdp, h, PGNO_BASE_MD, flags)) != 0 || 01877 (ret = CDB___bam_vrfy_meta(dbp, vdp, btmeta, PGNO_BASE_MD, flags)) != 0) 01878 goto err; 01879 01880 if (!F_ISSET(&btmeta->dbmeta, BTM_SUBDB)) { 01881 /* No subdbs, just return. */ 01882 ret = 0; 01883 goto err; 01884 } 01885 01886 /* We think we've got subdbs. Mark it so. */ 01887 *hassubsp = 1; 01888 01889 if ((ret = CDB_memp_fput(dbp->mpf, h, 0)) != 0) 01890 return (ret); 01891 01892 /* 01893 * We have subdbs. Try to crack them. 01894 * 01895 * To do so, get a set of leaf pages in the master 01896 * database, and then walk each of the valid ones, salvaging 01897 * subdbs as we go. If any prove invalid, just drop them; we'll 01898 * pick them up on a later pass. 01899 */ 01900 if ((ret = CDB___db_vrfy_pgset(dbp->dbenv, dbp->pgsize, &pgset)) != 0) 01901 return (ret); 01902 if ((ret = 01903 __db_meta2pgset(dbp, vdp, PGNO_BASE_MD, flags, pgset)) != 0) 01904 goto err; 01905 01906 if ((ret = pgset->cursor(pgset, NULL, &pgsc, 0)) != 0) 01907 goto err; 01908 while ((ret = CDB___db_vrfy_pgset_next(pgsc, &p)) == 0) { 01909 if ((ret = CDB_memp_fget(dbp->mpf, &p, 0, &h)) != 0) { 01910 err_ret = ret; 01911 continue; 01912 } 01913 if ((ret = __db_vrfy_common(dbp, vdp, h, p, flags)) != 0 || 01914 (ret = CDB___bam_vrfy(dbp, 01915 vdp, h, p, flags | DB_NOORDERCHK)) != 0) 01916 goto nextpg; 01917 if (TYPE(h) != P_LBTREE) 01918 goto nextpg; 01919 else if ((ret = CDB___db_salvage_subdbpg( 01920 dbp, vdp, h, handle, callback, flags)) != 0) 01921 err_ret = ret; 01922 nextpg: if ((ret = CDB_memp_fput(dbp->mpf, h, 0)) != 0) 01923 err_ret = ret; 01924 } 01925 01926 if (ret != DB_NOTFOUND) 01927 goto err; 01928 if ((ret = pgsc->c_close(pgsc)) != 0) 01929 goto err; 01930 01931 ret = pgset->close(pgset, 0); 01932 return ((ret == 0 && err_ret != 0) ? err_ret : ret); 01933 01934 /* NOTREACHED */ 01935 01936 err: if (pgsc != NULL) 01937 (void)pgsc->c_close(pgsc); 01938 if (pgset != NULL) 01939 (void)pgset->close(pgset, 0); 01940 (void)CDB_memp_fput(dbp->mpf, h, 0); 01941 return (ret); 01942 } 01943 01944 /* 01945 * CDB___db_salvage_subdbpg -- 01946 * Given a known-good leaf page in the master database, salvage all 01947 * leaf pages corresponding to each subdb. 01948 * 01949 * PUBLIC: int CDB___db_salvage_subdbpg 01950 * PUBLIC: __P((DB *, VRFY_DBINFO *, PAGE *, void *, 01951 * PUBLIC: int (*)(void *, const void *), u_int32_t)); 01952 */ 01953 int 01954 CDB___db_salvage_subdbpg(dbp, vdp, master, handle, callback, flags) 01955 DB *dbp; 01956 VRFY_DBINFO *vdp; 01957 PAGE *master; 01958 void *handle; 01959 int (*callback) __P((void *, const void *)); 01960 u_int32_t flags; 01961 { 01962 BKEYDATA *bkkey, *bkdata; 01963 BOVERFLOW *bo; 01964 DB *pgset; 01965 DBC *pgsc; 01966 DBT key; 01967 PAGE *subpg; 01968 db_indx_t i; 01969 db_pgno_t meta_pgno, p; 01970 int ret, err_ret, t_ret; 01971 char *subdbname; 01972 01973 ret = err_ret = 0; 01974 subdbname = NULL; 01975 01976 if ((ret = CDB___db_vrfy_pgset(dbp->dbenv, dbp->pgsize, &pgset)) != 0) 01977 return (ret); 01978 01979 /* 01980 * For each entry, get and salvage the set of pages 01981 * corresponding to that entry. 01982 */ 01983 for (i = 0; i < NUM_ENT(master); i += P_INDX) { 01984 bkkey = GET_BKEYDATA(master, i); 01985 bkdata = GET_BKEYDATA(master, i + O_INDX); 01986 01987 /* Get the subdatabase name. */ 01988 if (B_TYPE(bkkey->type) == B_OVERFLOW) { 01989 /* 01990 * We can, in principle anyway, have a subdb 01991 * name so long it overflows. Ick. 01992 */ 01993 bo = (BOVERFLOW *)bkkey; 01994 if ((ret = CDB___db_safe_goff(dbp, vdp, bo->pgno, &key, 01995 (void **)&subdbname, flags)) != 0) { 01996 err_ret = DB_VERIFY_BAD; 01997 continue; 01998 } 01999 02000 /* Nul-terminate it. */ 02001 if ((ret = CDB___os_realloc(dbp->dbenv, 02002 key.size + 1, NULL, &subdbname)) != 0) 02003 goto err; 02004 subdbname[key.size] = '0円'; 02005 } else if (B_TYPE(bkkey->type == B_KEYDATA)) { 02006 if ((ret = CDB___os_realloc(dbp->dbenv, 02007 bkkey->len + 1, NULL, &subdbname)) != 0) 02008 goto err; 02009 memcpy(subdbname, bkkey->data, bkkey->len); 02010 subdbname[bkkey->len] = '0円'; 02011 } 02012 02013 /* Get the corresponding pgno. */ 02014 if (bkdata->len != sizeof(db_pgno_t)) { 02015 err_ret = DB_VERIFY_BAD; 02016 continue; 02017 } 02018 memcpy(&meta_pgno, bkdata->data, sizeof(db_pgno_t)); 02019 02020 /* If we can't get the subdb meta page, just skip the subdb. */ 02021 if (!IS_VALID_PGNO(meta_pgno) || 02022 (ret = CDB_memp_fget(dbp->mpf, &meta_pgno, 0, &subpg)) != 0) { 02023 err_ret = ret; 02024 continue; 02025 } 02026 02027 /* 02028 * Verify the subdatabase meta page. This has two functions. 02029 * First, if it's bad, we have no choice but to skip the subdb 02030 * and let the pages just get printed on a later pass. Second, 02031 * the access-method-specific meta verification routines record 02032 * the various state info (such as the presence of dups) 02033 * that we need for CDB___db_prheader(). 02034 */ 02035 if ((ret = 02036 __db_vrfy_common(dbp, vdp, subpg, meta_pgno, flags)) != 0) { 02037 err_ret = ret; 02038 (void)CDB_memp_fput(dbp->mpf, subpg, 0); 02039 continue; 02040 } 02041 switch (TYPE(subpg)) { 02042 case P_BTREEMETA: 02043 if ((ret = CDB___bam_vrfy_meta(dbp, 02044 vdp, (BTMETA *)subpg, meta_pgno, flags)) != 0) { 02045 err_ret = ret; 02046 (void)CDB_memp_fput(dbp->mpf, subpg, 0); 02047 continue; 02048 } 02049 break; 02050 case P_HASHMETA: 02051 if ((ret = CDB___ham_vrfy_meta(dbp, 02052 vdp, (HMETA *)subpg, meta_pgno, flags)) != 0) { 02053 err_ret = ret; 02054 (void)CDB_memp_fput(dbp->mpf, subpg, 0); 02055 continue; 02056 } 02057 break; 02058 default: 02059 /* This isn't an appropriate page; skip this subdb. */ 02060 err_ret = DB_VERIFY_BAD; 02061 continue; 02062 /* NOTREACHED */ 02063 } 02064 02065 if ((ret = CDB_memp_fput(dbp->mpf, subpg, 0)) != 0) { 02066 err_ret = ret; 02067 continue; 02068 } 02069 02070 /* Print a subdatabase header. */ 02071 if ((ret = CDB___db_prheader(dbp, 02072 subdbname, 0, 0, handle, callback, vdp, meta_pgno)) != 0) 02073 goto err; 02074 02075 if ((ret = __db_meta2pgset(dbp, vdp, meta_pgno, 02076 flags, pgset)) != 0) { 02077 err_ret = ret; 02078 continue; 02079 } 02080 02081 if ((ret = pgset->cursor(pgset, NULL, &pgsc, 0)) != 0) 02082 goto err; 02083 while ((ret = CDB___db_vrfy_pgset_next(pgsc, &p)) == 0) { 02084 if ((ret = CDB_memp_fget(dbp->mpf, &p, 0, &subpg)) != 0) { 02085 err_ret = ret; 02086 continue; 02087 } 02088 if ((ret = CDB___db_salvage(dbp, vdp, p, subpg, 02089 handle, callback, flags)) != 0) 02090 err_ret = ret; 02091 if ((ret = CDB_memp_fput(dbp->mpf, subpg, 0)) != 0) 02092 err_ret = ret; 02093 } 02094 02095 if (ret != DB_NOTFOUND) 02096 goto err; 02097 02098 if ((ret = pgsc->c_close(pgsc)) != 0) 02099 goto err; 02100 if ((ret = CDB___db_prfooter(handle, callback)) != 0) 02101 goto err; 02102 } 02103 err: if (subdbname) 02104 CDB___os_free(subdbname, 0); 02105 02106 if ((t_ret = pgset->close(pgset, 0)) != 0) 02107 ret = t_ret; 02108 02109 if ((t_ret = CDB___db_salvage_markdone(vdp, PGNO(master))) != 0) 02110 return (t_ret); 02111 02112 return ((err_ret != 0) ? err_ret : ret); 02113 } 02114 02115 /* 02116 * __db_meta2pgset -- 02117 * Given a known-safe meta page number, return the set of pages 02118 * corresponding to the database it represents. Return DB_VERIFY_BAD if 02119 * it's not a suitable meta page or is invalid. 02120 */ 02121 static int 02122 __db_meta2pgset(dbp, vdp, pgno, flags, pgset) 02123 DB *dbp; 02124 VRFY_DBINFO *vdp; 02125 db_pgno_t pgno; 02126 u_int32_t flags; 02127 DB *pgset; 02128 { 02129 PAGE *h; 02130 int ret, t_ret; 02131 02132 if ((ret = CDB_memp_fget(dbp->mpf, &pgno, 0, &h)) != 0) 02133 return (ret); 02134 02135 switch (TYPE(h)) { 02136 case P_BTREEMETA: 02137 ret = CDB___bam_meta2pgset(dbp, vdp, (BTMETA *)h, flags, pgset); 02138 break; 02139 case P_HASHMETA: 02140 ret = CDB___ham_meta2pgset(dbp, vdp, (HMETA *)h, flags, pgset); 02141 break; 02142 default: 02143 ret = DB_VERIFY_BAD; 02144 break; 02145 } 02146 02147 if ((t_ret = CDB_memp_fput(dbp->mpf, h, 0)) != 0) 02148 return (t_ret); 02149 return (ret); 02150 } 02151 02152 /* 02153 * __db_guesspgsize -- 02154 * Try to guess what the pagesize is if the one on the meta page 02155 * and the one in the db are invalid. 02156 */ 02157 static int 02158 __db_guesspgsize(dbenv, fhp) 02159 DB_ENV *dbenv; 02160 DB_FH *fhp; 02161 { 02162 db_pgno_t i; 02163 size_t nr; 02164 u_int32_t guess; 02165 u_int8_t type; 02166 int ret; 02167 02168 for (guess = DB_MAX_PGSIZE; guess >= DB_MIN_PGSIZE; guess >>= 1) { 02169 /* 02170 * We try to read three pages ahead after the first one 02171 * and make sure we have plausible types for all of them. 02172 * If the seeks fail, continue with a smaller size; 02173 * we're probably just looking past the end of the database. 02174 * If they succeed but the types are wrong, also continue 02175 * with a size smaller; we may be looking at pages N, 02176 * 2N, and 3N for some N > 1. 02177 * 02178 * As soon as we hit an invalid type, we stop and return 02179 * our best guess; the last one was probably the page size. 02180 */ 02181 for (i = 1; i <= 3; i++) { 02182 if ((ret = CDB___os_seek(dbenv, fhp, guess, 02183 i, SSZ(DBMETA, type), 0, DB_OS_SEEK_SET)) != 0) 02184 break; 02185 if ((ret = CDB___os_read(dbenv, 02186 fhp, &type, 1, &nr)) != 0 || nr == 0) 02187 break; 02188 if (type == P_INVALID || type >= P_PAGETYPE_MAX) 02189 break; 02190 } 02191 } 02192 02193 return (guess); 02194 }