Main Page | Class Hierarchy | Data Structures | Directories | File List | Data Fields | Related Pages

db_vrfy.c

00001 /*-
00002  * See the file LICENSE for redistribution information.
00003  *
00004  * Copyright (c) 2000-2005
00005  *      Sleepycat Software.  All rights reserved.
00006  *
00007  * $Id: db_vrfy.c,v 12.14 2005/10/07 16:49:47 bostic Exp $
00008  */
00009 
00010 #include "db_config.h"
00011 
00012 #ifndef NO_SYSTEM_INCLUDES
00013 #include <sys/types.h>
00014 
00015 #include <string.h>
00016 #endif
00017 
00018 #include "db_int.h"
00019 #include "dbinc/db_page.h"
00020 #include "dbinc/db_shash.h"
00021 #include "dbinc/db_swap.h"
00022 #include "dbinc/db_verify.h"
00023 #include "dbinc/btree.h"
00024 #include "dbinc/hash.h"
00025 #include "dbinc/lock.h"
00026 #include "dbinc/mp.h"
00027 #include "dbinc/qam.h"
00028 #include "dbinc/txn.h"
00029 
00030 /*
00031  * This is the code for DB->verify, the DB database consistency checker.
00032  * For now, it checks all subdatabases in a database, and verifies
00033  * everything it knows how to (i.e. it's all-or-nothing, and one can't
00034  * check only for a subset of possible problems).
00035  */
00036 
00037 static u_int __db_guesspgsize __P((DB_ENV *, DB_FH *));
00038 static int   __db_is_valid_magicno __P((u_int32_t, DBTYPE *));
00039 static int   __db_is_valid_pagetype __P((u_int32_t));
00040 static int   __db_meta2pgset
00041                 __P((DB *, VRFY_DBINFO *, db_pgno_t, u_int32_t, DB *));
00042 static int   __db_salvage_subdbpg __P((DB *, VRFY_DBINFO *,
00043                 PAGE *, void *, int (*)(void *, const void *), u_int32_t));
00044 static int   __db_salvage_subdbs __P((DB *, VRFY_DBINFO *, void *,
00045                 int(*)(void *, const void *), u_int32_t, int *));
00046 static int   __db_salvage_unknowns __P((DB *, VRFY_DBINFO *, void *,
00047                 int (*)(void *, const void *), u_int32_t));
00048 static int   __db_verify __P((DB *, const char *, const char *,
00049                 void *, int (*)(void *, const void *), u_int32_t));
00050 static int   __db_verify_arg __P((DB *, const char *, void *, u_int32_t));
00051 static int   __db_vrfy_freelist
00052                 __P((DB *, VRFY_DBINFO *, db_pgno_t, u_int32_t));
00053 static int   __db_vrfy_invalid
00054                 __P((DB *, VRFY_DBINFO *, PAGE *, db_pgno_t, u_int32_t));
00055 static int   __db_vrfy_orderchkonly __P((DB *,
00056                 VRFY_DBINFO *, const char *, const char *, u_int32_t));
00057 static int   __db_vrfy_pagezero __P((DB *, VRFY_DBINFO *, DB_FH *, u_int32_t));
00058 static int   __db_vrfy_subdbs
00059                 __P((DB *, VRFY_DBINFO *, const char *, u_int32_t));
00060 static int   __db_vrfy_structure
00061                 __P((DB *, VRFY_DBINFO *, const char *, db_pgno_t, u_int32_t));
00062 static int   __db_vrfy_walkpages __P((DB *, VRFY_DBINFO *,
00063                 void *, int (*)(void *, const void *), u_int32_t));
00064 
00065 #define VERIFY_FLAGS                                                    \
00066     (DB_AGGRESSIVE |                                                    \
00067      DB_NOORDERCHK | DB_ORDERCHKONLY | DB_PRINTABLE | DB_SALVAGE | DB_UNREF)
00068 
00069 /*
00070  * __db_verify_pp --
00071  *      DB->verify public interface.
00072  *
00073  * PUBLIC: int __db_verify_pp
00074  * PUBLIC:     __P((DB *, const char *, const char *, FILE *, u_int32_t));
00075  */
00076 int
00077 __db_verify_pp(dbp, file, database, outfile, flags)
00078         DB *dbp;
00079         const char *file, *database;
00080         FILE *outfile;
00081         u_int32_t flags;
00082 {
00083         /*
00084          * __db_verify_pp is a wrapper to __db_verify_internal, which lets
00085          * us pass appropriate equivalents to FILE * in from the non-C APIs.
00086          */
00087         return (__db_verify_internal(dbp,
00088             file, database, outfile, __db_pr_callback, flags));
00089 }
00090 
00091 /*
00092  * __db_verify_internal --
00093  *
00094  * PUBLIC: int __db_verify_internal __P((DB *, const char *,
00095  * PUBLIC:     const char *, void *, int (*)(void *, const void *), u_int32_t));
00096  */
00097 int
00098 __db_verify_internal(dbp, fname, dname, handle, callback, flags)
00099         DB *dbp;
00100         const char *fname, *dname;
00101         void *handle;
00102         int (*callback) __P((void *, const void *));
00103         u_int32_t flags;
00104 {
00105         DB_ENV *dbenv;
00106         int ret, t_ret;
00107 
00108         dbenv = dbp->dbenv;
00109 
00110         PANIC_CHECK(dbenv);
00111         DB_ILLEGAL_AFTER_OPEN(dbp, "DB->verify");
00112 
00113 #ifdef HAVE_FTRUNCATE
00114         /*
00115          * If we're using ftruncate to abort page-allocation functions, there
00116          * should never be unreferenced pages.  Always check for unreferenced
00117          * pages on those systems.
00118          */
00119         if (!LF_ISSET(DB_SALVAGE))
00120                 LF_SET(DB_UNREF);
00121 #endif
00122 
00123         if ((ret = __db_verify_arg(dbp, dname, handle, flags)) == 0)
00124                 ret = __db_verify(dbp, fname, dname, handle, callback, flags);
00125 
00126         /* Db.verify is a DB handle destructor. */
00127         if ((t_ret = __db_close(dbp, NULL, 0)) != 0 && ret == 0)
00128                 ret = t_ret;
00129 
00130         return (ret);
00131 }
00132 
00133 /*
00134  * __db_verify_arg --
00135  *      Check DB->verify arguments.
00136  */
00137 static int
00138 __db_verify_arg(dbp, dname, handle, flags)
00139         DB *dbp;
00140         const char *dname;
00141         void *handle;
00142         u_int32_t flags;
00143 {
00144         DB_ENV *dbenv;
00145         int ret;
00146 
00147         dbenv = dbp->dbenv;
00148 
00149         if ((ret = __db_fchk(dbenv, "DB->verify", flags, VERIFY_FLAGS)) != 0)
00150                 return (ret);
00151 
00152         /*
00153          * DB_SALVAGE is mutually exclusive with the other flags except
00154          * DB_AGGRESSIVE, DB_PRINTABLE.
00155          *
00156          * DB_AGGRESSIVE and DB_PRINTABLE are only meaningful when salvaging.
00157          *
00158          * DB_SALVAGE requires an output stream.
00159          */
00160         if (LF_ISSET(DB_SALVAGE)) {
00161                 if (LF_ISSET(~(DB_AGGRESSIVE | DB_PRINTABLE | DB_SALVAGE)))
00162                         return (__db_ferr(dbenv, "DB->verify", 1));
00163                 if (handle == NULL) {
00164                         __db_err(dbenv,
00165                             "DB_SALVAGE requires a an output handle");
00166                         return (EINVAL);
00167                 }
00168         } else
00169                 if (LF_ISSET(DB_AGGRESSIVE | DB_PRINTABLE))
00170                         return (__db_ferr(dbenv, "DB->verify", 1));
00171 
00172         /*
00173          * DB_ORDERCHKONLY is mutually exclusive with DB_SALVAGE and
00174          * DB_NOORDERCHK, and requires a database name.
00175          */
00176         if ((ret = __db_fcchk(dbenv, "DB->verify", flags,
00177             DB_ORDERCHKONLY, DB_SALVAGE | DB_NOORDERCHK)) != 0)
00178                 return (ret);
00179         if (LF_ISSET(DB_ORDERCHKONLY) && dname == NULL) {
00180                 __db_err(dbenv, "DB_ORDERCHKONLY requires a database name");
00181                 return (EINVAL);
00182         }
00183         return (0);
00184 }
00185 
00186 /*
00187  * __db_verify --
00188  *      Walk the entire file page-by-page, either verifying with or without
00189  *      dumping in db_dump -d format, or DB_SALVAGE-ing whatever key/data
00190  *      pairs can be found and dumping them in standard (db_load-ready)
00191  *      dump format.
00192  *
00193  *      (Salvaging isn't really a verification operation, but we put it
00194  *      here anyway because it requires essentially identical top-level
00195  *      code.)
00196  *
00197  *      flags may be 0, DB_NOORDERCHK, DB_ORDERCHKONLY, or DB_SALVAGE
00198  *      (and optionally DB_AGGRESSIVE).
00199  */
00200 static int
00201 __db_verify(dbp, name, subdb, handle, callback, flags)
00202         DB *dbp;
00203         const char *name, *subdb;
00204         void *handle;
00205         int (*callback) __P((void *, const void *));
00206         u_int32_t flags;
00207 {
00208         DB_ENV *dbenv;
00209         DB_FH *fhp;
00210         VRFY_DBINFO *vdp;
00211         int has_subdbs, isbad, ret, t_ret;
00212         char *real_name;
00213 
00214         dbenv = dbp->dbenv;
00215         fhp = NULL;
00216         vdp = NULL;
00217         real_name = NULL;
00218         has_subdbs = isbad = ret = 0;
00219 
00220         F_SET(dbp, DB_AM_VERIFYING);
00221 
00222         /* Initialize any feedback function. */
00223         if (!LF_ISSET(DB_SALVAGE) && dbp->db_feedback != NULL)
00224                 dbp->db_feedback(dbp, DB_VERIFY, 0);
00225 
00226         /*
00227          * We don't know how large the cache is, and if the database
00228          * in question uses a small page size--which we don't know
00229          * yet!--it may be uncomfortably small for the default page
00230          * size [#2143].  However, the things we need temporary
00231          * databases for in dbinfo are largely tiny, so using a
00232          * 1024-byte pagesize is probably not going to be a big hit,
00233          * and will make us fit better into small spaces.
00234          */
00235         if ((ret = __db_vrfy_dbinfo_create(dbenv, 1024, &vdp)) != 0)
00236                 goto err;
00237 
00238         /*
00239          * Note whether the user has requested that we use printable
00240          * chars where possible.  We won't get here with this flag if
00241          * we're not salvaging.
00242          */
00243         if (LF_ISSET(DB_PRINTABLE))
00244                 F_SET(vdp, SALVAGE_PRINTABLE);
00245 
00246         /* Find the real name of the file. */
00247         if ((ret = __db_appname(dbenv,
00248             DB_APP_DATA, name, 0, NULL, &real_name)) != 0)
00249                 goto err;
00250 
00251         /*
00252          * Our first order of business is to verify page 0, which is
00253          * the metadata page for the master database of subdatabases
00254          * or of the only database in the file.  We want to do this by hand
00255          * rather than just calling __db_open in case it's corrupt--various
00256          * things in __db_open might act funny.
00257          *
00258          * Once we know the metadata page is healthy, I believe that it's
00259          * safe to open the database normally and then use the page swapping
00260          * code, which makes life easier.
00261          */
00262         if ((ret = __os_open(dbenv, real_name, DB_OSO_RDONLY, 0, &fhp)) != 0)
00263                 goto err;
00264 
00265         /* Verify the metadata page 0; set pagesize and type. */
00266         if ((ret = __db_vrfy_pagezero(dbp, vdp, fhp, flags)) != 0) {
00267                 if (ret == DB_VERIFY_BAD)
00268                         isbad = 1;
00269                 else
00270                         goto err;
00271         }
00272 
00273         /*
00274          * We can assume at this point that dbp->pagesize and dbp->type are
00275          * set correctly, or at least as well as they can be, and that
00276          * locking, logging, and txns are not in use.  Thus we can trust
00277          * the memp code not to look at the page, and thus to be safe
00278          * enough to use.
00279          *
00280          * The dbp is not open, but the file is open in the fhp, and we
00281          * cannot assume that __db_open is safe.  Call __db_dbenv_setup,
00282          * the [safe] part of __db_open that initializes the environment--
00283          * and the mpool--manually.
00284          */
00285         if ((ret = __db_dbenv_setup(dbp, NULL,
00286             name, subdb, TXN_INVALID, DB_ODDFILESIZE | DB_RDONLY)) != 0)
00287                 goto err;
00288 
00289         /*
00290          * Set our name in the Queue subsystem;  we may need it later
00291          * to deal with extents.
00292          */
00293         if (dbp->type == DB_QUEUE &&
00294             (ret = __qam_set_ext_data(dbp, name)) != 0)
00295                 goto err;
00296 
00297         /* Mark the dbp as opened, so that we correctly handle its close. */
00298         F_SET(dbp, DB_AM_OPEN_CALLED);
00299 
00300         /* Find out the page number of the last page in the database. */
00301         if ((ret = __memp_last_pgno(dbp->mpf, &vdp->last_pgno)) != 0)
00302                 goto err;
00303 
00304         /*
00305          * DB_ORDERCHKONLY is a special case;  our file consists of
00306          * several subdatabases, which use different hash, bt_compare,
00307          * and/or dup_compare functions.  Consequently, we couldn't verify
00308          * sorting and hashing simply by calling DB->verify() on the file.
00309          * DB_ORDERCHKONLY allows us to come back and check those things;  it
00310          * requires a subdatabase, and assumes that everything but that
00311          * database's sorting/hashing is correct.
00312          */
00313         if (LF_ISSET(DB_ORDERCHKONLY)) {
00314                 ret = __db_vrfy_orderchkonly(dbp, vdp, name, subdb, flags);
00315                 goto done;
00316         }
00317 
00318         /*
00319          * When salvaging, we use a db to keep track of whether we've seen a
00320          * given overflow or dup page in the course of traversing normal data.
00321          * If in the end we have not, we assume its key got lost and print it
00322          * with key "UNKNOWN".
00323          */
00324         if (LF_ISSET(DB_SALVAGE)) {
00325                 if ((ret = __db_salvage_init(vdp)) != 0)
00326                         goto err;
00327 
00328                 /*
00329                  * If we're not being aggressive, attempt to crack subdatabases.
00330                  * "has_subdbs" will indicate whether the attempt has succeeded
00331                  * (even in part), meaning that we have some semblance of
00332                  * subdatabases; on the walkpages pass, we print out whichever
00333                  * data pages we have not seen.
00334                  */
00335                 if (!LF_ISSET(DB_AGGRESSIVE) && __db_salvage_subdbs(
00336                     dbp, vdp, handle, callback, flags, &has_subdbs) != 0)
00337                         isbad = 1;
00338 
00339                 /*
00340                  * If we have subdatabases, flag if any keys are found that
00341                  * don't belong to a subdatabase -- they'll need to have an
00342                  * "__OTHER__" subdatabase header printed first.
00343                  */
00344                 if (has_subdbs)
00345                         F_SET(vdp, SALVAGE_PRINTHEADER);
00346         }
00347 
00348         if ((ret =
00349             __db_vrfy_walkpages(dbp, vdp, handle, callback, flags)) != 0) {
00350                 if (ret == DB_VERIFY_BAD)
00351                         isbad = 1;
00352                 else
00353                         goto err;
00354         }
00355 
00356         /* If we're verifying, verify inter-page structure. */
00357         if (!LF_ISSET(DB_SALVAGE) && isbad == 0)
00358                 if ((ret =
00359                     __db_vrfy_structure(dbp, vdp, name, 0, flags)) != 0) {
00360                         if (ret == DB_VERIFY_BAD)
00361                                 isbad = 1;
00362                         else
00363                                 goto err;
00364                 }
00365 
00366         /*
00367          * If we're salvaging, output with key UNKNOWN any overflow or dup pages
00368          * we haven't been able to put in context.  Then destroy the salvager's
00369          * state-saving database.
00370          */
00371         if (LF_ISSET(DB_SALVAGE)) {
00372                 if ((ret = __db_salvage_unknowns(dbp,
00373                     vdp, handle, callback, flags)) != 0)
00374                         isbad = 1;
00375                 /* No return value, since there's little we can do. */
00376                 __db_salvage_destroy(vdp);
00377         }
00378 
00379         /* Don't display a footer for a database holding other databases. */
00380         if (LF_ISSET(DB_SALVAGE) &&
00381             (!has_subdbs || F_ISSET(vdp, SALVAGE_PRINTFOOTER)))
00382                 (void)__db_prfooter(handle, callback);
00383 
00384 done: err:
00385         /* Send feedback that we're done. */
00386         if (!LF_ISSET(DB_SALVAGE) && dbp->db_feedback != NULL)
00387                 dbp->db_feedback(dbp, DB_VERIFY, 100);
00388 
00389         if (fhp != NULL &&
00390             (t_ret = __os_closehandle(dbenv, fhp)) != 0 && ret == 0)
00391                 ret = t_ret;
00392         if (vdp != NULL &&
00393             (t_ret = __db_vrfy_dbinfo_destroy(dbenv, vdp)) != 0 && ret == 0)
00394                 ret = t_ret;
00395         if (real_name != NULL)
00396                 __os_free(dbenv, real_name);
00397 
00398         /*
00399          * DB_VERIFY_FATAL is a private error, translate to a public one.
00400          *
00401          * If we didn't find a page, it's probably a page number was corrupted.
00402          * Return the standard corruption error.
00403          *
00404          * Otherwise, if we found corruption along the way, set the return.
00405          */
00406         if (ret == DB_VERIFY_FATAL ||
00407             ret == DB_PAGE_NOTFOUND || (ret == 0 && isbad == 1))
00408                 ret = DB_VERIFY_BAD;
00409 
00410         /* Make sure there's a public complaint if we found corruption. */
00411         if (ret != 0)
00412                 __db_err(dbenv, "%s: %s", name, db_strerror(ret));
00413 
00414         return (ret);
00415 }
00416 
00417 /*
00418  * __db_vrfy_pagezero --
00419  *      Verify the master metadata page.  Use seek, read, and a local buffer
00420  *      rather than the DB paging code, for safety.
00421  *
00422  *      Must correctly (or best-guess) set dbp->type and dbp->pagesize.
00423  */
00424 static int
00425 __db_vrfy_pagezero(dbp, vdp, fhp, flags)
00426         DB *dbp;
00427         VRFY_DBINFO *vdp;
00428         DB_FH *fhp;
00429         u_int32_t flags;
00430 {
00431         DBMETA *meta;
00432         DB_ENV *dbenv;
00433         VRFY_PAGEINFO *pip;
00434         db_pgno_t freelist;
00435         size_t nr;
00436         int isbad, ret, swapped;
00437         u_int8_t mbuf[DBMETASIZE];
00438 
00439         isbad = ret = swapped = 0;
00440         freelist = 0;
00441         dbenv = dbp->dbenv;
00442         meta = (DBMETA *)mbuf;
00443         dbp->type = DB_UNKNOWN;
00444 
00445         if ((ret = __db_vrfy_getpageinfo(vdp, PGNO_BASE_MD, &pip)) != 0)
00446                 return (ret);
00447 
00448         /*
00449          * Seek to the metadata page.
00450          * Note that if we're just starting a verification, dbp->pgsize
00451          * may be zero;  this is okay, as we want page zero anyway and
00452          * 0*0 == 0.
00453          */
00454         if ((ret = __os_seek(dbenv, fhp, 0, 0, 0, 0, DB_OS_SEEK_SET)) != 0 ||
00455             (ret = __os_read(dbenv, fhp, mbuf, DBMETASIZE, &nr)) != 0) {
00456                 __db_err(dbenv,
00457                     "Metadata page %lu cannot be read: %s",
00458                     (u_long)PGNO_BASE_MD, db_strerror(ret));
00459                 return (ret);
00460         }
00461 
00462         if (nr != DBMETASIZE) {
00463                 EPRINT((dbenv,
00464                     "Page %lu: Incomplete metadata page",
00465                     (u_long)PGNO_BASE_MD));
00466                 return (DB_VERIFY_FATAL);
00467         }
00468 
00469         if ((ret = __db_chk_meta(dbenv, dbp, meta, 1)) != 0) {
00470                 EPRINT((dbenv,
00471                     "Page %lu: metadata page corrupted", (u_long)PGNO_BASE_MD));
00472                 isbad = 1;
00473                 if (ret != -1) {
00474                         EPRINT((dbenv,
00475                             "Page %lu: could not check metadata page",
00476                             (u_long)PGNO_BASE_MD));
00477                         return (DB_VERIFY_FATAL);
00478                 }
00479         }
00480 
00481         /*
00482          * Check all of the fields that we can.
00483          *
00484          * 08-11: Current page number.  Must == pgno.
00485          * Note that endianness doesn't matter--it's zero.
00486          */
00487         if (meta->pgno != PGNO_BASE_MD) {
00488                 isbad = 1;
00489                 EPRINT((dbenv, "Page %lu: pgno incorrectly set to %lu",
00490                     (u_long)PGNO_BASE_MD, (u_long)meta->pgno));
00491         }
00492 
00493         /* 12-15: Magic number.  Must be one of valid set. */
00494         if (__db_is_valid_magicno(meta->magic, &dbp->type))
00495                 swapped = 0;
00496         else {
00497                 M_32_SWAP(meta->magic);
00498                 if (__db_is_valid_magicno(meta->magic,
00499                     &dbp->type))
00500                         swapped = 1;
00501                 else {
00502                         isbad = 1;
00503                         EPRINT((dbenv,
00504                             "Page %lu: bad magic number %lu",
00505                             (u_long)PGNO_BASE_MD, (u_long)meta->magic));
00506                 }
00507         }
00508 
00509         /*
00510          * 16-19: Version.  Must be current;  for now, we
00511          * don't support verification of old versions.
00512          */
00513         if (swapped)
00514                 M_32_SWAP(meta->version);
00515         if ((dbp->type == DB_BTREE &&
00516             (meta->version > DB_BTREEVERSION ||
00517             meta->version < DB_BTREEOLDVER)) ||
00518             (dbp->type == DB_HASH &&
00519             (meta->version > DB_HASHVERSION ||
00520             meta->version < DB_HASHOLDVER)) ||
00521             (dbp->type == DB_QUEUE &&
00522             (meta->version > DB_QAMVERSION ||
00523             meta->version < DB_QAMOLDVER))) {
00524                 isbad = 1;
00525                 EPRINT((dbenv,
00526     "Page %lu: unsupported DB version %lu; extraneous errors may result",
00527                     (u_long)PGNO_BASE_MD, (u_long)meta->version));
00528         }
00529 
00530         /*
00531          * 20-23: Pagesize.  Must be power of two,
00532          * greater than 512, and less than 64K.
00533          */
00534         if (swapped)
00535                 M_32_SWAP(meta->pagesize);
00536         if (IS_VALID_PAGESIZE(meta->pagesize))
00537                 dbp->pgsize = meta->pagesize;
00538         else {
00539                 isbad = 1;
00540                 EPRINT((dbenv, "Page %lu: bad page size %lu",
00541                     (u_long)PGNO_BASE_MD, (u_long)meta->pagesize));
00542 
00543                 /*
00544                  * Now try to settle on a pagesize to use.
00545                  * If the user-supplied one is reasonable,
00546                  * use it;  else, guess.
00547                  */
00548                 if (!IS_VALID_PAGESIZE(dbp->pgsize))
00549                         dbp->pgsize = __db_guesspgsize(dbenv, fhp);
00550         }
00551 
00552         /*
00553          * 25: Page type.  Must be correct for dbp->type,
00554          * which is by now set as well as it can be.
00555          */
00556         /* Needs no swapping--only one byte! */
00557         if ((dbp->type == DB_BTREE && meta->type != P_BTREEMETA) ||
00558             (dbp->type == DB_HASH && meta->type != P_HASHMETA) ||
00559             (dbp->type == DB_QUEUE && meta->type != P_QAMMETA)) {
00560                 isbad = 1;
00561                 EPRINT((dbenv, "Page %lu: bad page type %lu",
00562                     (u_long)PGNO_BASE_MD, (u_long)meta->type));
00563         }
00564 
00565         /*
00566          * 26: Meta-flags.
00567          */
00568         if (meta->metaflags != 0) {
00569                 if (meta->metaflags == DBMETA_CHKSUM)
00570                         F_SET(pip, VRFY_HAS_CHKSUM);
00571                 else {
00572                         isbad = 1;
00573                         EPRINT((dbenv,
00574                             "Page %lu: bad meta-data flags value %#lx",
00575                             (u_long)PGNO_BASE_MD, (u_long)meta->metaflags));
00576                 }
00577         }
00578 
00579         /*
00580          * 28-31: Free list page number.
00581          * We'll verify its sensibility when we do inter-page
00582          * verification later;  for now, just store it.
00583          */
00584         if (swapped)
00585             M_32_SWAP(meta->free);
00586         freelist = meta->free;
00587 
00588         /*
00589          * Initialize vdp->pages to fit a single pageinfo structure for
00590          * this one page.  We'll realloc later when we know how many
00591          * pages there are.
00592          */
00593         pip->pgno = PGNO_BASE_MD;
00594         pip->type = meta->type;
00595 
00596         /*
00597          * Signal that we still have to check the info specific to
00598          * a given type of meta page.
00599          */
00600         F_SET(pip, VRFY_INCOMPLETE);
00601 
00602         pip->free = freelist;
00603 
00604         if ((ret = __db_vrfy_putpageinfo(dbenv, vdp, pip)) != 0)
00605                 return (ret);
00606 
00607         /* Set up the dbp's fileid.  We don't use the regular open path. */
00608         memcpy(dbp->fileid, meta->uid, DB_FILE_ID_LEN);
00609 
00610         if (swapped == 1)
00611                 F_SET(dbp, DB_AM_SWAP);
00612 
00613         return (isbad ? DB_VERIFY_BAD : 0);
00614 }
00615 
00616 /*
00617  * __db_vrfy_walkpages --
00618  *      Main loop of the verifier/salvager.  Walks through,
00619  *      page by page, and verifies all pages and/or prints all data pages.
00620  */
00621 static int
00622 __db_vrfy_walkpages(dbp, vdp, handle, callback, flags)
00623         DB *dbp;
00624         VRFY_DBINFO *vdp;
00625         void *handle;
00626         int (*callback) __P((void *, const void *));
00627         u_int32_t flags;
00628 {
00629         DB_ENV *dbenv;
00630         DB_MPOOLFILE *mpf;
00631         PAGE *h;
00632         db_pgno_t i;
00633         int ret, t_ret, isbad;
00634 
00635         dbenv = dbp->dbenv;
00636         mpf = dbp->mpf;
00637         h = NULL;
00638         ret = isbad = t_ret = 0;
00639 
00640         for (i = 0; i <= vdp->last_pgno; i++) {
00641                 /*
00642                  * If DB_SALVAGE is set, we inspect our database of completed
00643                  * pages, and skip any we've already printed in the subdb pass.
00644                  */
00645                 if (LF_ISSET(DB_SALVAGE) && (__db_salvage_isdone(vdp, i) != 0))
00646                         continue;
00647 
00648                 /*
00649                  * If an individual page get fails, keep going if and only
00650                  * if we're salvaging.
00651                  */
00652                 if ((t_ret = __memp_fget(mpf, &i, 0, &h)) != 0) {
00653                         if (ret == 0)
00654                                 ret = t_ret;
00655                         if (LF_ISSET(DB_SALVAGE))
00656                                 continue;
00657                         return (ret);
00658                 }
00659 
00660                 if (LF_ISSET(DB_SALVAGE)) {
00661                         /*
00662                          * We pretty much don't want to quit unless a
00663                          * bomb hits.  May as well return that something
00664                          * was screwy, however.
00665                          */
00666                         if ((t_ret = __db_salvage(dbp,
00667                             vdp, i, h, handle, callback, flags)) != 0) {
00668                                 if (ret == 0)
00669                                         ret = t_ret;
00670                                 isbad = 1;
00671                         }
00672                 } else {
00673                         /*
00674                          * If we are not salvaging, and we get any error
00675                          * other than DB_VERIFY_BAD, return immediately;
00676                          * it may not be safe to proceed.  If we get
00677                          * DB_VERIFY_BAD, keep going;  listing more errors
00678                          * may make it easier to diagnose problems and
00679                          * determine the magnitude of the corruption.
00680                          *
00681                          * Verify info common to all page types.
00682                          */
00683                         if (i != PGNO_BASE_MD) {
00684                                 ret = __db_vrfy_common(dbp, vdp, h, i, flags);
00685                                 if (ret == DB_VERIFY_BAD)
00686                                         isbad = 1;
00687                                 else if (ret != 0)
00688                                         goto err;
00689                         }
00690 
00691                         switch (TYPE(h)) {
00692                         case P_INVALID:
00693                                 ret = __db_vrfy_invalid(dbp, vdp, h, i, flags);
00694                                 break;
00695                         case __P_DUPLICATE:
00696                                 isbad = 1;
00697                                 EPRINT((dbenv,
00698                                     "Page %lu: old-style duplicate page",
00699                                     (u_long)i));
00700                                 break;
00701                         case P_HASH:
00702                                 ret = __ham_vrfy(dbp, vdp, h, i, flags);
00703                                 break;
00704                         case P_IBTREE:
00705                         case P_IRECNO:
00706                         case P_LBTREE:
00707                         case P_LDUP:
00708                                 ret = __bam_vrfy(dbp, vdp, h, i, flags);
00709                                 break;
00710                         case P_LRECNO:
00711                                 ret = __ram_vrfy_leaf(dbp, vdp, h, i, flags);
00712                                 break;
00713                         case P_OVERFLOW:
00714                                 ret = __db_vrfy_overflow(dbp, vdp, h, i, flags);
00715                                 break;
00716                         case P_HASHMETA:
00717                                 ret = __ham_vrfy_meta(dbp,
00718                                     vdp, (HMETA *)h, i, flags);
00719                                 break;
00720                         case P_BTREEMETA:
00721                                 ret = __bam_vrfy_meta(dbp,
00722                                     vdp, (BTMETA *)h, i, flags);
00723                                 break;
00724                         case P_QAMMETA:
00725                                 ret = __qam_vrfy_meta(dbp,
00726                                     vdp, (QMETA *)h, i, flags);
00727                                 break;
00728                         case P_QAMDATA:
00729                                 ret = __qam_vrfy_data(dbp,
00730                                     vdp, (QPAGE *)h, i, flags);
00731                                 break;
00732                         default:
00733                                 EPRINT((dbenv,
00734                                     "Page %lu: unknown page type %lu",
00735                                     (u_long)i, (u_long)TYPE(h)));
00736                                 isbad = 1;
00737                                 break;
00738                         }
00739 
00740                         /*
00741                          * Set up error return.
00742                          */
00743                         if (ret == DB_VERIFY_BAD)
00744                                 isbad = 1;
00745                         else if (ret != 0)
00746                                 goto err;
00747 
00748                         /*
00749                          * Provide feedback to the application about our
00750                          * progress.  The range 0-50% comes from the fact
00751                          * that this is the first of two passes through the
00752                          * database (front-to-back, then top-to-bottom).
00753                          */
00754                         if (dbp->db_feedback != NULL)
00755                                 dbp->db_feedback(dbp, DB_VERIFY,
00756                                     (int)((i + 1) * 50 / (vdp->last_pgno + 1)));
00757                 }
00758 
00759                 /*
00760                  * Just as with the page get, bail if and only if we're
00761                  * not salvaging.
00762                  */
00763                 if ((t_ret = __memp_fput(mpf, h, 0)) != 0) {
00764                         if (ret == 0)
00765                                 ret = t_ret;
00766                         if (!LF_ISSET(DB_SALVAGE))
00767                                 return (ret);
00768                 }
00769         }
00770 
00771         /*
00772          * If we've seen a Queue metadata page, we may need to walk Queue
00773          * extent pages that won't show up between 0 and vdp->last_pgno.
00774          */
00775         if (F_ISSET(vdp, VRFY_QMETA_SET) && (t_ret =
00776             __qam_vrfy_walkqueue(dbp, vdp, handle, callback, flags)) != 0) {
00777                 if (ret == 0)
00778                         ret = t_ret;
00779                 if (t_ret == DB_VERIFY_BAD)
00780                         isbad = 1;
00781                 else if (!LF_ISSET(DB_SALVAGE))
00782                         return (ret);
00783         }
00784 
00785         if (0) {
00786 err:            if (h != NULL && (t_ret = __memp_fput(mpf, h, 0)) != 0)
00787                         return (ret == 0 ? t_ret : ret);
00788         }
00789 
00790         return ((isbad == 1 && ret == 0) ? DB_VERIFY_BAD : ret);
00791 }
00792 
00793 /*
00794  * __db_vrfy_structure--
00795  *      After a beginning-to-end walk through the database has been
00796  *      completed, put together the information that has been collected
00797  *      to verify the overall database structure.
00798  *
00799  *      Should only be called if we want to do a database verification,
00800  *      i.e. if DB_SALVAGE is not set.
00801  */
00802 static int
00803 __db_vrfy_structure(dbp, vdp, dbname, meta_pgno, flags)
00804         DB *dbp;
00805         VRFY_DBINFO *vdp;
00806         const char *dbname;
00807         db_pgno_t meta_pgno;
00808         u_int32_t flags;
00809 {
00810         DB *pgset;
00811         DB_ENV *dbenv;
00812         VRFY_PAGEINFO *pip;
00813         db_pgno_t i;
00814         int ret, isbad, hassubs, p;
00815 
00816         isbad = 0;
00817         pip = NULL;
00818         dbenv = dbp->dbenv;
00819         pgset = vdp->pgset;
00820 
00821         /*
00822          * Providing feedback here is tricky;  in most situations,
00823          * we fetch each page one more time, but we do so in a top-down
00824          * order that depends on the access method.  Worse, we do this
00825          * recursively in btree, such that on any call where we're traversing
00826          * a subtree we don't know where that subtree is in the whole database;
00827          * worse still, any given database may be one of several subdbs.
00828          *
00829          * The solution is to decrement a counter vdp->pgs_remaining each time
00830          * we verify (and call feedback on) a page.  We may over- or
00831          * under-count, but the structure feedback function will ensure that we
00832          * never give a percentage under 50 or over 100.  (The first pass
00833          * covered the range 0-50%.)
00834          */
00835         if (dbp->db_feedback != NULL)
00836                 vdp->pgs_remaining = vdp->last_pgno + 1;
00837 
00838         /*
00839          * Call the appropriate function to downwards-traverse the db type.
00840          */
00841         switch (dbp->type) {
00842         case DB_BTREE:
00843         case DB_RECNO:
00844                 if ((ret = __bam_vrfy_structure(dbp, vdp, 0, flags)) != 0) {
00845                         if (ret == DB_VERIFY_BAD)
00846                                 isbad = 1;
00847                         else
00848                                 goto err;
00849                 }
00850 
00851                 /*
00852                  * If we have subdatabases and we know that the database is,
00853                  * thus far, sound, it's safe to walk the tree of subdatabases.
00854                  * Do so, and verify the structure of the databases within.
00855                  */
00856                 if ((ret = __db_vrfy_getpageinfo(vdp, 0, &pip)) != 0)
00857                         goto err;
00858                 hassubs = F_ISSET(pip, VRFY_HAS_SUBDBS) ? 1 : 0;
00859                 if ((ret = __db_vrfy_putpageinfo(dbenv, vdp, pip)) != 0)
00860                         goto err;
00861                 pip = NULL;
00862 
00863                 if (isbad == 0 && hassubs)
00864                         if ((ret =
00865                             __db_vrfy_subdbs(dbp, vdp, dbname, flags)) != 0) {
00866                                 if (ret == DB_VERIFY_BAD)
00867                                         isbad = 1;
00868                                 else
00869                                         goto err;
00870                         }
00871                 break;
00872         case DB_HASH:
00873                 if ((ret = __ham_vrfy_structure(dbp, vdp, 0, flags)) != 0) {
00874                         if (ret == DB_VERIFY_BAD)
00875                                 isbad = 1;
00876                         else
00877                                 goto err;
00878                 }
00879                 break;
00880         case DB_QUEUE:
00881                 if ((ret = __qam_vrfy_structure(dbp, vdp, flags)) != 0) {
00882                         if (ret == DB_VERIFY_BAD)
00883                                 isbad = 1;
00884                 }
00885 
00886                 /*
00887                  * Queue pages may be unreferenced and totally zeroed, if
00888                  * they're empty;  queue doesn't have much structure, so
00889                  * this is unlikely to be wrong in any troublesome sense.
00890                  * Skip to "err".
00891                  */
00892                 goto err;
00893         case DB_UNKNOWN:
00894         default:
00895                 /* This should only happen if the verifier is somehow broken. */
00896                 DB_ASSERT(0);
00897                 ret = EINVAL;
00898                 goto err;
00899         }
00900 
00901         /* Walk free list. */
00902         if ((ret =
00903             __db_vrfy_freelist(dbp, vdp, meta_pgno, flags)) == DB_VERIFY_BAD)
00904                 isbad = 1;
00905 
00906         /*
00907          * If structure checks up until now have failed, it's likely that
00908          * checking what pages have been missed will result in oodles of
00909          * extraneous error messages being EPRINTed.  Skip to the end
00910          * if this is the case;  we're going to be printing at least one
00911          * error anyway, and probably all the more salient ones.
00912          */
00913         if (ret != 0 || isbad == 1)
00914                 goto err;
00915 
00916         /*
00917          * Make sure no page has been missed and that no page is still marked
00918          * "all zeroes" (only certain hash pages can be, and they're unmarked
00919          * in __ham_vrfy_structure).
00920          */
00921         for (i = 0; i < vdp->last_pgno + 1; i++) {
00922                 if ((ret = __db_vrfy_getpageinfo(vdp, i, &pip)) != 0)
00923                         goto err;
00924                 if ((ret = __db_vrfy_pgset_get(pgset, i, &p)) != 0)
00925                         goto err;
00926                 if (pip->type == P_OVERFLOW) {
00927                         if ((u_int32_t)p != pip->refcount) {
00928                                 EPRINT((dbenv,
00929                     "Page %lu: overflow refcount %lu, referenced %lu times",
00930                                     (u_long)i,
00931                                     (u_long)pip->refcount, (u_long)p));
00932                                 isbad = 1;
00933                         }
00934                 } else if (p == 0 && LF_ISSET(DB_UNREF)) {
00935                         EPRINT((dbenv,
00936                             "Page %lu: unreferenced page", (u_long)i));
00937                         isbad = 1;
00938                 }
00939 
00940                 if (F_ISSET(pip, VRFY_IS_ALLZEROES)) {
00941                         EPRINT((dbenv,
00942                             "Page %lu: totally zeroed page", (u_long)i));
00943                         isbad = 1;
00944                 }
00945                 if ((ret = __db_vrfy_putpageinfo(dbenv, vdp, pip)) != 0)
00946                         goto err;
00947                 pip = NULL;
00948         }
00949 
00950 err:    if (pip != NULL)
00951                 (void)__db_vrfy_putpageinfo(dbenv, vdp, pip);
00952 
00953         return ((isbad == 1 && ret == 0) ? DB_VERIFY_BAD : ret);
00954 }
00955 
00956 /*
00957  * __db_is_valid_pagetype
00958  */
00959 static int
00960 __db_is_valid_pagetype(type)
00961         u_int32_t type;
00962 {
00963         switch (type) {
00964         case P_INVALID:                 /* Order matches ordinal value. */
00965         case P_HASH:
00966         case P_IBTREE:
00967         case P_IRECNO:
00968         case P_LBTREE:
00969         case P_LRECNO:
00970         case P_OVERFLOW:
00971         case P_HASHMETA:
00972         case P_BTREEMETA:
00973         case P_QAMMETA:
00974         case P_QAMDATA:
00975         case P_LDUP:
00976                 return (1);
00977         default:
00978                 break;
00979         }
00980         return (0);
00981 }
00982 
00983 /*
00984  * __db_is_valid_magicno
00985  */
00986 static int
00987 __db_is_valid_magicno(magic, typep)
00988         u_int32_t magic;
00989         DBTYPE *typep;
00990 {
00991         switch (magic) {
00992         case DB_BTREEMAGIC:
00993                 *typep = DB_BTREE;
00994                 return (1);
00995         case DB_HASHMAGIC:
00996                 *typep = DB_HASH;
00997                 return (1);
00998         case DB_QAMMAGIC:
00999                 *typep = DB_QUEUE;
01000                 return (1);
01001         default:
01002                 break;
01003         }
01004         *typep = DB_UNKNOWN;
01005         return (0);
01006 }
01007 
01008 /*
01009  * __db_vrfy_common --
01010  *      Verify info common to all page types.
01011  *
01012  * PUBLIC: int  __db_vrfy_common
01013  * PUBLIC:     __P((DB *, VRFY_DBINFO *, PAGE *, db_pgno_t, u_int32_t));
01014  */
01015 int
01016 __db_vrfy_common(dbp, vdp, h, pgno, flags)
01017         DB *dbp;
01018         VRFY_DBINFO *vdp;
01019         PAGE *h;
01020         db_pgno_t pgno;
01021         u_int32_t flags;
01022 {
01023         DB_ENV *dbenv;
01024         VRFY_PAGEINFO *pip;
01025         int ret, t_ret;
01026         u_int8_t *p;
01027 
01028         dbenv = dbp->dbenv;
01029 
01030         if ((ret = __db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0)
01031                 return (ret);
01032 
01033         pip->pgno = pgno;
01034         F_CLR(pip, VRFY_IS_ALLZEROES);
01035 
01036         /*
01037          * Hash expands the table by leaving some pages between the
01038          * old last and the new last totally zeroed.  Its pgin function
01039          * should fix things, but we might not be using that (e.g. if
01040          * we're a subdatabase).
01041          *
01042          * Queue will create sparse files if sparse record numbers are used.
01043          */
01044         if (pgno != 0 && PGNO(h) == 0) {
01045                 for (p = (u_int8_t *)h; p < (u_int8_t *)h + dbp->pgsize; p++)
01046                         if (*p != 0) {
01047                                 EPRINT((dbenv,
01048                                     "Page %lu: partially zeroed page",
01049                                     (u_long)pgno));
01050                                 ret = DB_VERIFY_BAD;
01051                                 goto err;
01052                         }
01053                 /*
01054                  * It's totally zeroed;  mark it as a hash, and we'll
01055                  * check that that makes sense structurally later.
01056                  * (The queue verification doesn't care, since queues
01057                  * don't really have much in the way of structure.)
01058                  */
01059                 pip->type = P_HASH;
01060                 F_SET(pip, VRFY_IS_ALLZEROES);
01061                 ret = 0;
01062                 goto err;       /* well, not really an err. */
01063         }
01064 
01065         if (PGNO(h) != pgno) {
01066                 EPRINT((dbenv, "Page %lu: bad page number %lu",
01067                     (u_long)pgno, (u_long)h->pgno));
01068                 ret = DB_VERIFY_BAD;
01069         }
01070 
01071         if (!__db_is_valid_pagetype(h->type)) {
01072                 EPRINT((dbenv, "Page %lu: bad page type %lu",
01073                     (u_long)pgno, (u_long)h->type));
01074                 ret = DB_VERIFY_BAD;
01075         }
01076         pip->type = h->type;
01077 
01078 err:    if ((t_ret = __db_vrfy_putpageinfo(dbenv, vdp, pip)) != 0 && ret == 0)
01079                 ret = t_ret;
01080 
01081         return (ret);
01082 }
01083 
01084 /*
01085  * __db_vrfy_invalid --
01086  *      Verify P_INVALID page.
01087  *      (Yes, there's not much to do here.)
01088  */
01089 static int
01090 __db_vrfy_invalid(dbp, vdp, h, pgno, flags)
01091         DB *dbp;
01092         VRFY_DBINFO *vdp;
01093         PAGE *h;
01094         db_pgno_t pgno;
01095         u_int32_t flags;
01096 {
01097         DB_ENV *dbenv;
01098         VRFY_PAGEINFO *pip;
01099         int ret, t_ret;
01100 
01101         dbenv = dbp->dbenv;
01102 
01103         if ((ret = __db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0)
01104                 return (ret);
01105         pip->next_pgno = pip->prev_pgno = 0;
01106 
01107         if (!IS_VALID_PGNO(NEXT_PGNO(h))) {
01108                 EPRINT((dbenv, "Page %lu: invalid next_pgno %lu",
01109                     (u_long)pgno, (u_long)NEXT_PGNO(h)));
01110                 ret = DB_VERIFY_BAD;
01111         } else
01112                 pip->next_pgno = NEXT_PGNO(h);
01113 
01114         if ((t_ret = __db_vrfy_putpageinfo(dbenv, vdp, pip)) != 0 && ret == 0)
01115                 ret = t_ret;
01116         return (ret);
01117 }
01118 
01119 /*
01120  * __db_vrfy_datapage --
01121  *      Verify elements common to data pages (P_HASH, P_LBTREE,
01122  *      P_IBTREE, P_IRECNO, P_LRECNO, P_OVERFLOW, P_DUPLICATE)--i.e.,
01123  *      those defined in the PAGE structure.
01124  *
01125  *      Called from each of the per-page routines, after the
01126  *      all-page-type-common elements of pip have been verified and filled
01127  *      in.
01128  *
01129  * PUBLIC: int __db_vrfy_datapage
01130  * PUBLIC:     __P((DB *, VRFY_DBINFO *, PAGE *, db_pgno_t, u_int32_t));
01131  */
01132 int
01133 __db_vrfy_datapage(dbp, vdp, h, pgno, flags)
01134         DB *dbp;
01135         VRFY_DBINFO *vdp;
01136         PAGE *h;
01137         db_pgno_t pgno;
01138         u_int32_t flags;
01139 {
01140         DB_ENV *dbenv;
01141         VRFY_PAGEINFO *pip;
01142         int isbad, ret, t_ret;
01143 
01144         dbenv = dbp->dbenv;
01145 
01146         if ((ret = __db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0)
01147                 return (ret);
01148         isbad = 0;
01149 
01150         /*
01151          * prev_pgno and next_pgno:  store for inter-page checks,
01152          * verify that they point to actual pages and not to self.
01153          *
01154          * !!!
01155          * Internal btree pages do not maintain these fields (indeed,
01156          * they overload them).  Skip.
01157          */
01158         if (TYPE(h) != P_IBTREE && TYPE(h) != P_IRECNO) {
01159                 if (!IS_VALID_PGNO(PREV_PGNO(h)) || PREV_PGNO(h) == pip->pgno) {
01160                         isbad = 1;
01161                         EPRINT((dbenv, "Page %lu: invalid prev_pgno %lu",
01162                             (u_long)pip->pgno, (u_long)PREV_PGNO(h)));
01163                 }
01164                 if (!IS_VALID_PGNO(NEXT_PGNO(h)) || NEXT_PGNO(h) == pip->pgno) {
01165                         isbad = 1;
01166                         EPRINT((dbenv, "Page %lu: invalid next_pgno %lu",
01167                             (u_long)pip->pgno, (u_long)NEXT_PGNO(h)));
01168                 }
01169                 pip->prev_pgno = PREV_PGNO(h);
01170                 pip->next_pgno = NEXT_PGNO(h);
01171         }
01172 
01173         /*
01174          * Verify the number of entries on the page.
01175          * There is no good way to determine if this is accurate;  the
01176          * best we can do is verify that it's not more than can, in theory,
01177          * fit on the page.  Then, we make sure there are at least
01178          * this many valid elements in inp[], and hope that this catches
01179          * most cases.
01180          */
01181         if (TYPE(h) != P_OVERFLOW) {
01182                 if (BKEYDATA_PSIZE(0) * NUM_ENT(h) > dbp->pgsize) {
01183                         isbad = 1;
01184                         EPRINT((dbenv, "Page %lu: too many entries: %lu",
01185                             (u_long)pgno, (u_long)NUM_ENT(h)));
01186                 }
01187                 pip->entries = NUM_ENT(h);
01188         }
01189 
01190         /*
01191          * btree level.  Should be zero unless we're a btree;
01192          * if we are a btree, should be between LEAFLEVEL and MAXBTREELEVEL,
01193          * and we need to save it off.
01194          */
01195         switch (TYPE(h)) {
01196         case P_IBTREE:
01197         case P_IRECNO:
01198                 if (LEVEL(h) < LEAFLEVEL + 1) {
01199                         isbad = 1;
01200                         EPRINT((dbenv, "Page %lu: bad btree level %lu",
01201                             (u_long)pgno, (u_long)LEVEL(h)));
01202                 }
01203                 pip->bt_level = LEVEL(h);
01204                 break;
01205         case P_LBTREE:
01206         case P_LDUP:
01207         case P_LRECNO:
01208                 if (LEVEL(h) != LEAFLEVEL) {
01209                         isbad = 1;
01210                         EPRINT((dbenv,
01211                             "Page %lu: btree leaf page has incorrect level %lu",
01212                             (u_long)pgno, (u_long)LEVEL(h)));
01213                 }
01214                 break;
01215         default:
01216                 if (LEVEL(h) != 0) {
01217                         isbad = 1;
01218                         EPRINT((dbenv,
01219                             "Page %lu: nonzero level %lu in non-btree database",
01220                             (u_long)pgno, (u_long)LEVEL(h)));
01221                 }
01222                 break;
01223         }
01224 
01225         /*
01226          * Even though inp[] occurs in all PAGEs, we look at it in the
01227          * access-method-specific code, since btree and hash treat
01228          * item lengths very differently, and one of the most important
01229          * things we want to verify is that the data--as specified
01230          * by offset and length--cover the right part of the page
01231          * without overlaps, gaps, or violations of the page boundary.
01232          */
01233         if ((t_ret = __db_vrfy_putpageinfo(dbenv, vdp, pip)) != 0 && ret == 0)
01234                 ret = t_ret;
01235 
01236         return ((ret == 0 && isbad == 1) ? DB_VERIFY_BAD : ret);
01237 }
01238 
01239 /*
01240  * __db_vrfy_meta--
01241  *      Verify the access-method common parts of a meta page, using
01242  *      normal mpool routines.
01243  *
01244  * PUBLIC: int __db_vrfy_meta
01245  * PUBLIC:     __P((DB *, VRFY_DBINFO *, DBMETA *, db_pgno_t, u_int32_t));
01246  */
01247 int
01248 __db_vrfy_meta(dbp, vdp, meta, pgno, flags)
01249         DB *dbp;
01250         VRFY_DBINFO *vdp;
01251         DBMETA *meta;
01252         db_pgno_t pgno;
01253         u_int32_t flags;
01254 {
01255         DB_ENV *dbenv;
01256         DBTYPE dbtype, magtype;
01257         VRFY_PAGEINFO *pip;
01258         int isbad, ret, t_ret;
01259 
01260         isbad = 0;
01261         dbenv = dbp->dbenv;
01262 
01263         if ((ret = __db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0)
01264                 return (ret);
01265 
01266         /* type plausible for a meta page */
01267         switch (meta->type) {
01268         case P_BTREEMETA:
01269                 dbtype = DB_BTREE;
01270                 break;
01271         case P_HASHMETA:
01272                 dbtype = DB_HASH;
01273                 break;
01274         case P_QAMMETA:
01275                 dbtype = DB_QUEUE;
01276                 break;
01277         default:
01278                 /* The verifier should never let us get here. */
01279                 DB_ASSERT(0);
01280                 ret = EINVAL;
01281                 goto err;
01282         }
01283 
01284         /* magic number valid */
01285         if (!__db_is_valid_magicno(meta->magic, &magtype)) {
01286                 isbad = 1;
01287                 EPRINT((dbenv,
01288                     "Page %lu: invalid magic number", (u_long)pgno));
01289         }
01290         if (magtype != dbtype) {
01291                 isbad = 1;
01292                 EPRINT((dbenv,
01293                     "Page %lu: magic number does not match database type",
01294                     (u_long)pgno));
01295         }
01296 
01297         /* version */
01298         if ((dbtype == DB_BTREE &&
01299             (meta->version > DB_BTREEVERSION ||
01300             meta->version < DB_BTREEOLDVER)) ||
01301             (dbtype == DB_HASH &&
01302             (meta->version > DB_HASHVERSION ||
01303             meta->version < DB_HASHOLDVER)) ||
01304             (dbtype == DB_QUEUE &&
01305             (meta->version > DB_QAMVERSION ||
01306             meta->version < DB_QAMOLDVER))) {
01307                 isbad = 1;
01308                 EPRINT((dbenv,
01309     "Page %lu: unsupported database version %lu; extraneous errors may result",
01310                     (u_long)pgno, (u_long)meta->version));
01311         }
01312 
01313         /* pagesize */
01314         if (meta->pagesize != dbp->pgsize) {
01315                 isbad = 1;
01316                 EPRINT((dbenv, "Page %lu: invalid pagesize %lu",
01317                     (u_long)pgno, (u_long)meta->pagesize));
01318         }
01319 
01320         /* Flags */
01321         if (meta->metaflags != 0) {
01322                 if (meta->metaflags == DBMETA_CHKSUM)
01323                         F_SET(pip, VRFY_HAS_CHKSUM);
01324                 else {
01325                         isbad = 1;
01326                         EPRINT((dbenv,
01327                             "Page %lu: bad meta-data flags value %#lx",
01328                             (u_long)PGNO_BASE_MD, (u_long)meta->metaflags));
01329                 }
01330         }
01331 
01332         /*
01333          * Free list.
01334          *
01335          * If this is not the main, master-database meta page, it
01336          * should not have a free list.
01337          */
01338         if (pgno != PGNO_BASE_MD && meta->free != PGNO_INVALID) {
01339                 isbad = 1;
01340                 EPRINT((dbenv,
01341                     "Page %lu: nonempty free list on subdatabase metadata page",
01342                     (u_long)pgno));
01343         }
01344 
01345         /* Can correctly be PGNO_INVALID--that's just the end of the list. */
01346         if (meta->free != PGNO_INVALID && IS_VALID_PGNO(meta->free))
01347                 pip->free = meta->free;
01348         else if (!IS_VALID_PGNO(meta->free)) {
01349                 isbad = 1;
01350                 EPRINT((dbenv,
01351                     "Page %lu: nonsensical free list pgno %lu",
01352                     (u_long)pgno, (u_long)meta->free));
01353         }
01354 
01355         /*
01356          * We have now verified the common fields of the metadata page.
01357          * Clear the flag that told us they had been incompletely checked.
01358          */
01359         F_CLR(pip, VRFY_INCOMPLETE);
01360 
01361 err:    if ((t_ret = __db_vrfy_putpageinfo(dbenv, vdp, pip)) != 0 && ret == 0)
01362                 ret = t_ret;
01363 
01364         return ((ret == 0 && isbad == 1) ? DB_VERIFY_BAD : ret);
01365 }
01366 
01367 /*
01368  * __db_vrfy_freelist --
01369  *      Walk free list, checking off pages and verifying absence of
01370  *      loops.
01371  */
01372 static int
01373 __db_vrfy_freelist(dbp, vdp, meta, flags)
01374         DB *dbp;
01375         VRFY_DBINFO *vdp;
01376         db_pgno_t meta;
01377         u_int32_t flags;
01378 {
01379         DB *pgset;
01380         DB_ENV *dbenv;
01381         VRFY_PAGEINFO *pip;
01382         db_pgno_t cur_pgno, next_pgno;
01383         int p, ret, t_ret;
01384 
01385         pgset = vdp->pgset;
01386         DB_ASSERT(pgset != NULL);
01387         dbenv = dbp->dbenv;
01388 
01389         if ((ret = __db_vrfy_getpageinfo(vdp, meta, &pip)) != 0)
01390                 return (ret);
01391         for (next_pgno = pip->free;
01392             next_pgno != PGNO_INVALID; next_pgno = pip->next_pgno) {
01393                 cur_pgno = pip->pgno;
01394                 if ((ret = __db_vrfy_putpageinfo(dbenv, vdp, pip)) != 0)
01395                         return (ret);
01396 
01397                 /* This shouldn't happen, but just in case. */
01398                 if (!IS_VALID_PGNO(next_pgno)) {
01399                         EPRINT((dbenv,
01400                             "Page %lu: invalid next_pgno %lu on free list page",
01401                             (u_long)cur_pgno, (u_long)next_pgno));
01402                         return (DB_VERIFY_BAD);
01403                 }
01404 
01405                 /* Detect cycles. */
01406                 if ((ret = __db_vrfy_pgset_get(pgset, next_pgno, &p)) != 0)
01407                         return (ret);
01408                 if (p != 0) {
01409                         EPRINT((dbenv,
01410                     "Page %lu: page %lu encountered a second time on free list",
01411                             (u_long)cur_pgno, (u_long)next_pgno));
01412                         return (DB_VERIFY_BAD);
01413                 }
01414                 if ((ret = __db_vrfy_pgset_inc(pgset, next_pgno)) != 0)
01415                         return (ret);
01416 
01417                 if ((ret = __db_vrfy_getpageinfo(vdp, next_pgno, &pip)) != 0)
01418                         return (ret);
01419 
01420                 if (pip->type != P_INVALID) {
01421                         EPRINT((dbenv,
01422                             "Page %lu: non-invalid page %lu on free list",
01423                             (u_long)cur_pgno, (u_long)next_pgno));
01424                         ret = DB_VERIFY_BAD;      /* unsafe to continue */
01425                         break;
01426                 }
01427         }
01428 
01429         if ((t_ret = __db_vrfy_putpageinfo(dbenv, vdp, pip)) != 0)
01430                 ret = t_ret;
01431         return (ret);
01432 }
01433 
01434 /*
01435  * __db_vrfy_subdbs --
01436  *      Walk the known-safe master database of subdbs with a cursor,
01437  *      verifying the structure of each subdatabase we encounter.
01438  */
01439 static int
01440 __db_vrfy_subdbs(dbp, vdp, dbname, flags)
01441         DB *dbp;
01442         VRFY_DBINFO *vdp;
01443         const char *dbname;
01444         u_int32_t flags;
01445 {
01446         DB *mdbp;
01447         DBC *dbc;
01448         DBT key, data;
01449         DB_ENV *dbenv;
01450         VRFY_PAGEINFO *pip;
01451         db_pgno_t meta_pgno;
01452         int ret, t_ret, isbad;
01453         u_int8_t type;
01454 
01455         isbad = 0;
01456         dbc = NULL;
01457         dbenv = dbp->dbenv;
01458 
01459         if ((ret =
01460             __db_master_open(dbp, NULL, dbname, DB_RDONLY, 0, &mdbp)) != 0)
01461                 return (ret);
01462 
01463         if ((ret = __db_cursor_int(mdbp,
01464             NULL, DB_BTREE, PGNO_INVALID, 0, DB_LOCK_INVALIDID, &dbc)) != 0)
01465                 goto err;
01466 
01467         memset(&key, 0, sizeof(key));
01468         memset(&data, 0, sizeof(data));
01469         while ((ret = __db_c_get(dbc, &key, &data, DB_NEXT)) == 0) {
01470                 if (data.size != sizeof(db_pgno_t)) {
01471                         EPRINT((dbenv,
01472                             "Subdatabase entry not page-number size"));
01473                         isbad = 1;
01474                         goto err;
01475                 }
01476                 memcpy(&meta_pgno, data.data, data.size);
01477                 /*
01478                  * Subdatabase meta pgnos are stored in network byte
01479                  * order for cross-endian compatibility.  Swap if appropriate.
01480                  */
01481                 DB_NTOHL(&meta_pgno);
01482                 if (meta_pgno == PGNO_INVALID || meta_pgno > vdp->last_pgno) {
01483                         EPRINT((dbenv,
01484                     "Subdatabase entry references invalid page %lu",
01485                             (u_long)meta_pgno));
01486                         isbad = 1;
01487                         goto err;
01488                 }
01489                 if ((ret = __db_vrfy_getpageinfo(vdp, meta_pgno, &pip)) != 0)
01490                         goto err;
01491                 type = pip->type;
01492                 if ((ret = __db_vrfy_putpageinfo(dbenv, vdp, pip)) != 0)
01493                         goto err;
01494                 switch (type) {
01495                 case P_BTREEMETA:
01496                         if ((ret = __bam_vrfy_structure(
01497                             dbp, vdp, meta_pgno, flags)) != 0) {
01498                                 if (ret == DB_VERIFY_BAD)
01499                                         isbad = 1;
01500                                 else
01501                                         goto err;
01502                         }
01503                         break;
01504                 case P_HASHMETA:
01505                         if ((ret = __ham_vrfy_structure(
01506                             dbp, vdp, meta_pgno, flags)) != 0) {
01507                                 if (ret == DB_VERIFY_BAD)
01508                                         isbad = 1;
01509                                 else
01510                                         goto err;
01511                         }
01512                         break;
01513                 case P_QAMMETA:
01514                 default:
01515                         EPRINT((dbenv,
01516                     "Subdatabase entry references page %lu of invalid type %lu",
01517                             (u_long)meta_pgno, (u_long)type));
01518                         ret = DB_VERIFY_BAD;
01519                         goto err;
01520                 }
01521         }
01522 
01523         if (ret == DB_NOTFOUND)
01524                 ret = 0;
01525 
01526 err:    if (dbc != NULL && (t_ret = __db_c_close(dbc)) != 0 && ret == 0)
01527                 ret = t_ret;
01528 
01529         if ((t_ret = __db_close(mdbp, NULL, 0)) != 0 && ret == 0)
01530                 ret = t_ret;
01531 
01532         return ((ret == 0 && isbad == 1) ? DB_VERIFY_BAD : ret);
01533 }
01534 
01535 /*
01536  * __db_vrfy_struct_feedback --
01537  *      Provide feedback during top-down database structure traversal.
01538  *      (See comment at the beginning of __db_vrfy_structure.)
01539  *
01540  * PUBLIC: void __db_vrfy_struct_feedback __P((DB *, VRFY_DBINFO *));
01541  */
01542 void
01543 __db_vrfy_struct_feedback(dbp, vdp)
01544         DB *dbp;
01545         VRFY_DBINFO *vdp;
01546 {
01547         int progress;
01548 
01549         if (dbp->db_feedback == NULL)
01550                 return;
01551 
01552         if (vdp->pgs_remaining > 0)
01553                 vdp->pgs_remaining--;
01554 
01555         /* Don't allow a feedback call of 100 until we're really done. */
01556         progress = 100 - (int)(vdp->pgs_remaining * 50 / (vdp->last_pgno + 1));
01557         dbp->db_feedback(dbp, DB_VERIFY, progress == 100 ? 99 : progress);
01558 }
01559 
01560 /*
01561  * __db_vrfy_orderchkonly --
01562  *      Do an sort-order/hashing check on a known-otherwise-good subdb.
01563  */
01564 static int
01565 __db_vrfy_orderchkonly(dbp, vdp, name, subdb, flags)
01566         DB *dbp;
01567         VRFY_DBINFO *vdp;
01568         const char *name, *subdb;
01569         u_int32_t flags;
01570 {
01571         BTMETA *btmeta;
01572         DB *mdbp, *pgset;
01573         DBC *pgsc;
01574         DBT key, data;
01575         DB_ENV *dbenv;
01576         DB_MPOOLFILE *mpf;
01577         HASH *h_internal;
01578         HMETA *hmeta;
01579         PAGE *h, *currpg;
01580         db_pgno_t meta_pgno, p, pgno;
01581         u_int32_t bucket;
01582         int t_ret, ret;
01583 
01584         pgset = NULL;
01585         pgsc = NULL;
01586         dbenv = dbp->dbenv;
01587         mpf = dbp->mpf;
01588         currpg = h = NULL;
01589 
01590         LF_CLR(DB_NOORDERCHK);
01591 
01592         /* Open the master database and get the meta_pgno for the subdb. */
01593         if ((ret = __db_master_open(dbp, NULL, name, DB_RDONLY, 0, &mdbp)) != 0)
01594                 goto err;
01595 
01596         memset(&key, 0, sizeof(key));
01597         key.data = (void *)subdb;
01598         key.size = (u_int32_t)strlen(subdb);
01599         memset(&data, 0, sizeof(data));
01600         if ((ret = __db_get(mdbp, NULL, &key, &data, 0)) != 0)
01601                 goto err;
01602 
01603         if (data.size != sizeof(db_pgno_t)) {
01604                 EPRINT((dbenv, "Subdatabase entry of invalid size"));
01605                 ret = DB_VERIFY_BAD;
01606                 goto err;
01607         }
01608 
01609         memcpy(&meta_pgno, data.data, data.size);
01610 
01611         /*
01612          * Subdatabase meta pgnos are stored in network byte
01613          * order for cross-endian compatibility.  Swap if appropriate.
01614          */
01615         DB_NTOHL(&meta_pgno);
01616 
01617         if ((ret = __memp_fget(mpf, &meta_pgno, 0, &h)) != 0)
01618                 goto err;
01619 
01620         if ((ret = __db_vrfy_pgset(dbenv, dbp->pgsize, &pgset)) != 0)
01621                 goto err;
01622 
01623         switch (TYPE(h)) {
01624         case P_BTREEMETA:
01625                 btmeta = (BTMETA *)h;
01626                 if (F_ISSET(&btmeta->dbmeta, BTM_RECNO)) {
01627                         /* Recnos have no order to check. */
01628                         ret = 0;
01629                         goto err;
01630                 }
01631                 if ((ret =
01632                     __db_meta2pgset(dbp, vdp, meta_pgno, flags, pgset)) != 0)
01633                         goto err;
01634                 if ((ret = __db_cursor_int(pgset, NULL, dbp->type,
01635                     PGNO_INVALID, 0, DB_LOCK_INVALIDID, &pgsc)) != 0)
01636                         goto err;
01637                 while ((ret = __db_vrfy_pgset_next(pgsc, &p)) == 0) {
01638                         if ((ret = __memp_fget(mpf, &p, 0, &currpg)) != 0)
01639                                 goto err;
01640                         if ((ret = __bam_vrfy_itemorder(dbp,
01641                             NULL, currpg, p, NUM_ENT(currpg), 1,
01642                             F_ISSET(&btmeta->dbmeta, BTM_DUP), flags)) != 0)
01643                                 goto err;
01644                         if ((ret = __memp_fput(mpf, currpg, 0)) != 0)
01645                                 goto err;
01646                         currpg = NULL;
01647                 }
01648 
01649                 /*
01650                  * The normal exit condition for the loop above is DB_NOTFOUND.
01651                  * If we see that, zero it and continue on to cleanup.
01652                  * Otherwise, it's a real error and will be returned.
01653                  */
01654                 if (ret == DB_NOTFOUND)
01655                         ret = 0;
01656                 break;
01657         case P_HASHMETA:
01658                 hmeta = (HMETA *)h;
01659                 h_internal = (HASH *)dbp->h_internal;
01660                 /*
01661                  * Make sure h_charkey is right.
01662                  */
01663                 if (h_internal == NULL) {
01664                         EPRINT((dbenv,
01665                             "Page %lu: DB->h_internal field is NULL",
01666                             (u_long)meta_pgno));
01667                         ret = DB_VERIFY_BAD;
01668                         goto err;
01669                 }
01670                 if (h_internal->h_hash == NULL)
01671                         h_internal->h_hash = hmeta->dbmeta.version < 5
01672                         ? __ham_func4 : __ham_func5;
01673                 if (hmeta->h_charkey !=
01674                     h_internal->h_hash(dbp, CHARKEY, sizeof(CHARKEY))) {
01675                         EPRINT((dbenv,
01676                             "Page %lu: incorrect hash function for database",
01677                             (u_long)meta_pgno));
01678                         ret = DB_VERIFY_BAD;
01679                         goto err;
01680                 }
01681 
01682                 /*
01683                  * Foreach bucket, verify hashing on each page in the
01684                  * corresponding chain of pages.
01685                  */
01686                 for (bucket = 0; bucket <= hmeta->max_bucket; bucket++) {
01687                         pgno = BS_TO_PAGE(bucket, hmeta->spares);
01688                         while (pgno != PGNO_INVALID) {
01689                                 if ((ret = __memp_fget(mpf,
01690                                     &pgno, 0, &currpg)) != 0)
01691                                         goto err;
01692                                 if ((ret = __ham_vrfy_hashing(dbp,
01693                                     NUM_ENT(currpg), hmeta, bucket, pgno,
01694                                     flags, h_internal->h_hash)) != 0)
01695                                         goto err;
01696                                 pgno = NEXT_PGNO(currpg);
01697                                 if ((ret = __memp_fput(mpf, currpg, 0)) != 0)
01698                                         goto err;
01699                                 currpg = NULL;
01700                         }
01701                 }
01702                 break;
01703         default:
01704                 EPRINT((dbenv, "Page %lu: database metapage of bad type %lu",
01705                     (u_long)meta_pgno, (u_long)TYPE(h)));
01706                 ret = DB_VERIFY_BAD;
01707                 break;
01708         }
01709 
01710 err:    if (pgsc != NULL && (t_ret = __db_c_close(pgsc)) != 0 && ret == 0)
01711                 ret = t_ret;
01712         if (pgset != NULL &&
01713             (t_ret = __db_close(pgset, NULL, 0)) != 0 && ret == 0)
01714                 ret = t_ret;
01715         if (h != NULL && (t_ret = __memp_fput(mpf, h, 0)) != 0)
01716                 ret = t_ret;
01717         if (currpg != NULL && (t_ret = __memp_fput(mpf, currpg, 0)) != 0)
01718                 ret = t_ret;
01719         if ((t_ret = __db_close(mdbp, NULL, 0)) != 0)
01720                 ret = t_ret;
01721         return (ret);
01722 }
01723 
01724 /*
01725  * __db_salvage --
01726  *      Walk through a page, salvaging all likely or plausible (w/
01727  *      DB_AGGRESSIVE) key/data pairs.
01728  *
01729  * PUBLIC: int __db_salvage __P((DB *, VRFY_DBINFO *, db_pgno_t,
01730  * PUBLIC:     PAGE *, void *, int (*)(void *, const void *), u_int32_t));
01731  */
01732 int
01733 __db_salvage(dbp, vdp, pgno, h, handle, callback, flags)
01734         DB *dbp;
01735         VRFY_DBINFO *vdp;
01736         db_pgno_t pgno;
01737         PAGE *h;
01738         void *handle;
01739         int (*callback) __P((void *, const void *));
01740         u_int32_t flags;
01741 {
01742         DB_ENV *dbenv;
01743         VRFY_PAGEINFO *pip;
01744         int keyflag, ret, t_ret;
01745 
01746         DB_ASSERT(LF_ISSET(DB_SALVAGE));
01747 
01748         dbenv = dbp->dbenv;
01749 
01750         /*
01751          * !!!
01752          * We dump record numbers when salvaging Queue databases, but not for
01753          * immutable Recno databases.  The problem is we can't figure out the
01754          * record number from the database page in the Recno case, while the
01755          * offset in the file is sufficient for Queue.
01756          */
01757         keyflag = 0;
01758 
01759         /* If we got this page in the subdb pass, we can safely skip it. */
01760         if (__db_salvage_isdone(vdp, pgno))
01761                 return (0);
01762 
01763         switch (TYPE(h)) {
01764         case P_HASHMETA:
01765                 ret = __ham_vrfy_meta(dbp, vdp, (HMETA *)h, pgno, flags);
01766                 break;
01767         case P_BTREEMETA:
01768                 ret = __bam_vrfy_meta(dbp, vdp, (BTMETA *)h, pgno, flags);
01769                 break;
01770         case P_QAMMETA:
01771                 keyflag = 1;
01772                 ret = __qam_vrfy_meta(dbp, vdp, (QMETA *)h, pgno, flags);
01773                 break;
01774         case P_HASH:
01775                 return (__ham_salvage(
01776                     dbp, vdp, pgno, h, handle, callback, flags));
01777         case P_LBTREE:
01778                 return (__bam_salvage(dbp,
01779                     vdp, pgno, P_LBTREE, h, handle, callback, NULL, flags));
01780         case P_LDUP:
01781                 return (__db_salvage_markneeded(vdp, pgno, SALVAGE_LDUP));
01782         case P_OVERFLOW:
01783                 return (__db_salvage_markneeded(vdp, pgno, SALVAGE_OVERFLOW));
01784         case P_LRECNO:
01785                 /*
01786                  * Recnos are tricky -- they may represent dup pages, or
01787                  * they may be subdatabase/regular database pages in their
01788                  * own right.  If the former, they need to be printed with a
01789                  * key, preferably when we hit the corresponding datum in
01790                  * a btree/hash page.  If the latter, there is no key.
01791                  *
01792                  * If a database is sufficiently frotzed, we're not going
01793                  * to be able to get this right, so we best-guess:  just
01794                  * mark it needed now, and if we're really a normal recno
01795                  * database page, the "unknowns" pass will pick us up.
01796                  */
01797                 return (__db_salvage_markneeded(vdp, pgno, SALVAGE_LRECNO));
01798         case P_QAMDATA:
01799                 return (__qam_salvage(dbp,
01800                     vdp, pgno, h, handle, callback, flags));
01801         case P_IBTREE:
01802         case P_INVALID:
01803         case P_IRECNO:
01804         case __P_DUPLICATE:
01805         default:
01806                 /* XXX: Should we be more aggressive here? */
01807                 return (0);
01808         }
01809         if (ret != 0)
01810                 return (ret);
01811 
01812         /*
01813          * We have to display the dump header if it's a metadata page.  It's
01814          * our last chance as the page was marked "seen" in the vrfy routine,
01815          * and  we won't see the page again.  We don't display headers for
01816          * the first database in a multi-database file, that database simply
01817          * contains a list of subdatabases.
01818          */
01819         if ((ret = __db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0)
01820                 return (ret);
01821         if (!F_ISSET(pip, VRFY_HAS_SUBDBS))
01822                 ret = __db_prheader(
01823                     dbp, NULL, 0, keyflag, handle, callback, vdp, pgno);
01824         if ((t_ret = __db_vrfy_putpageinfo(dbenv, vdp, pip)) != 0 && ret == 0)
01825                 ret = t_ret;
01826         return (ret);
01827 }
01828 
01829 /*
01830  * __db_salvage_unknowns --
01831  *      Walk through the salvager database, printing with key "UNKNOWN"
01832  *      any pages we haven't dealt with.
01833  */
01834 static int
01835 __db_salvage_unknowns(dbp, vdp, handle, callback, flags)
01836         DB *dbp;
01837         VRFY_DBINFO *vdp;
01838         void *handle;
01839         int (*callback) __P((void *, const void *));
01840         u_int32_t flags;
01841 {
01842         DBC *dbc;
01843         DBT unkdbt, key, *dbt;
01844         DB_ENV *dbenv;
01845         DB_MPOOLFILE *mpf;
01846         PAGE *h;
01847         db_pgno_t pgno;
01848         u_int32_t pgtype;
01849         int ret, t_ret;
01850         void *ovflbuf;
01851 
01852         dbc = NULL;
01853         dbenv = dbp->dbenv;
01854         mpf = dbp->mpf;
01855 
01856         memset(&unkdbt, 0, sizeof(DBT));
01857         unkdbt.size = (u_int32_t)strlen("UNKNOWN") + 1;
01858         unkdbt.data = "UNKNOWN";
01859 
01860         if ((ret = __os_malloc(dbenv, dbp->pgsize, &ovflbuf)) != 0)
01861                 return (ret);
01862 
01863         /*
01864          * We make two passes -- in the first pass, skip SALVAGE_OVERFLOW
01865          * pages, because they may be referenced by the standard database
01866          * pages that we're resolving.
01867          */
01868         while ((t_ret =
01869             __db_salvage_getnext(vdp, &dbc, &pgno, &pgtype, 1)) == 0) {
01870                 if ((t_ret = __memp_fget(mpf, &pgno, 0, &h)) != 0) {
01871                         if (ret == 0)
01872                                 ret = t_ret;
01873                         continue;
01874                 }
01875 
01876                 dbt = NULL;
01877                 switch (pgtype) {
01878                 case SALVAGE_LDUP:
01879                 case SALVAGE_LRECNODUP:
01880                         dbt = &unkdbt;
01881                         /* FALLTHROUGH */
01882                 case SALVAGE_LBTREE:
01883                 case SALVAGE_LRECNO:
01884                         if ((t_ret = __bam_salvage(dbp, vdp, pgno, pgtype,
01885                             h, handle, callback, dbt, flags)) != 0 && ret == 0)
01886                                 ret = t_ret;
01887                         break;
01888                 case SALVAGE_OVERFLOW:
01889                         DB_ASSERT(0);           /* Shouldn't ever happen. */
01890                         break;
01891                 case SALVAGE_HASH:
01892                         if ((t_ret = __ham_salvage(dbp, vdp,
01893                             pgno, h, handle, callback, flags)) != 0 && ret == 0)
01894                                 ret = t_ret;
01895                         break;
01896                 case SALVAGE_INVALID:
01897                 case SALVAGE_IGNORE:
01898                 default:
01899                         /*
01900                          * Shouldn't happen, but if it does, just do what the
01901                          * nice man says.
01902                          */
01903                         DB_ASSERT(0);
01904                         break;
01905                 }
01906                 if ((t_ret = __memp_fput(mpf, h, 0)) != 0 && ret == 0)
01907                         ret = t_ret;
01908         }
01909 
01910         /* We should have reached the end of the database. */
01911         if (t_ret == DB_NOTFOUND)
01912                 t_ret = 0;
01913         if (t_ret != 0 && ret == 0)
01914                 ret = t_ret;
01915 
01916         /* Re-open the cursor so we traverse the database again. */
01917         if ((t_ret = __db_c_close(dbc)) != 0 && ret == 0)
01918                 ret = t_ret;
01919         dbc = NULL;
01920 
01921         /* Now, deal with any remaining overflow pages. */
01922         while ((t_ret =
01923             __db_salvage_getnext(vdp, &dbc, &pgno, &pgtype, 0)) == 0) {
01924                 if ((t_ret = __memp_fget(mpf, &pgno, 0, &h)) != 0) {
01925                         if (ret == 0)
01926                                 ret = t_ret;
01927                         continue;
01928                 }
01929 
01930                 switch (pgtype) {
01931                 case SALVAGE_OVERFLOW:
01932                         /*
01933                          * XXX:
01934                          * This may generate multiple "UNKNOWN" keys in
01935                          * a database with no dups.  What to do?
01936                          */
01937                         if ((t_ret = __db_safe_goff(dbp,
01938                             vdp, pgno, &key, &ovflbuf, flags)) != 0 ||
01939                             ((vdp->type == DB_BTREE || vdp->type == DB_HASH) &&
01940                             (t_ret = __db_vrfy_prdbt(&unkdbt,
01941                             0, " ", handle, callback, 0, vdp)) != 0) ||
01942                             (t_ret = __db_vrfy_prdbt(
01943                             &key, 0, " ", handle, callback, 0, vdp)) != 0)
01944                                 if (ret == 0)
01945                                         ret = t_ret;
01946                         break;
01947                 default:
01948                         DB_ASSERT(0);           /* Shouldn't ever happen. */
01949                         break;
01950                 }
01951                 if ((t_ret = __memp_fput(mpf, h, 0)) != 0 && ret == 0)
01952                         ret = t_ret;
01953         }
01954 
01955         /* We should have reached the end of the database. */
01956         if (t_ret == DB_NOTFOUND)
01957                 t_ret = 0;
01958         if (t_ret != 0 && ret == 0)
01959                 ret = t_ret;
01960 
01961         if ((t_ret = __db_c_close(dbc)) != 0 && ret == 0)
01962                 ret = t_ret;
01963 
01964         __os_free(dbenv, ovflbuf);
01965 
01966         return (ret);
01967 }
01968 
01969 /*
01970  * Offset of the ith inp array entry, which we can compare to the offset
01971  * the entry stores.
01972  */
01973 #define INP_OFFSET(dbp, h, i)   \
01974     ((db_indx_t)((u_int8_t *)((P_INP(dbp,(h))) + (i)) - (u_int8_t *)(h)))
01975 
01976 /*
01977  * __db_vrfy_inpitem --
01978  *      Verify that a single entry in the inp array is sane, and update
01979  *      the high water mark and current item offset.  (The former of these is
01980  *      used for state information between calls, and is required;  it must
01981  *      be initialized to the pagesize before the first call.)
01982  *
01983  *      Returns DB_VERIFY_FATAL if inp has collided with the data,
01984  *      since verification can't continue from there;  returns DB_VERIFY_BAD
01985  *      if anything else is wrong.
01986  *
01987  * PUBLIC: int __db_vrfy_inpitem __P((DB *, PAGE *,
01988  * PUBLIC:     db_pgno_t, u_int32_t, int, u_int32_t, u_int32_t *, u_int32_t *));
01989  */
01990 int
01991 __db_vrfy_inpitem(dbp, h, pgno, i, is_btree, flags, himarkp, offsetp)
01992         DB *dbp;
01993         PAGE *h;
01994         db_pgno_t pgno;
01995         u_int32_t i;
01996         int is_btree;
01997         u_int32_t flags, *himarkp, *offsetp;
01998 {
01999         BKEYDATA *bk;
02000         DB_ENV *dbenv;
02001         db_indx_t *inp, offset, len;
02002 
02003         dbenv = dbp->dbenv;
02004 
02005         DB_ASSERT(himarkp != NULL);
02006         inp = P_INP(dbp, h);
02007 
02008         /*
02009          * Check that the inp array, which grows from the beginning of the
02010          * page forward, has not collided with the data, which grow from the
02011          * end of the page backward.
02012          */
02013         if (inp + i >= (db_indx_t *)((u_int8_t *)h + *himarkp)) {
02014                 /* We've collided with the data.  We need to bail. */
02015                 EPRINT((dbenv, "Page %lu: entries listing %lu overlaps data",
02016                     (u_long)pgno, (u_long)i));
02017                 return (DB_VERIFY_FATAL);
02018         }
02019 
02020         offset = inp[i];
02021 
02022         /*
02023          * Check that the item offset is reasonable:  it points somewhere
02024          * after the inp array and before the end of the page.
02025          */
02026         if (offset <= INP_OFFSET(dbp, h, i) || offset > dbp->pgsize) {
02027                 EPRINT((dbenv, "Page %lu: bad offset %lu at page index %lu",
02028                     (u_long)pgno, (u_long)offset, (u_long)i));
02029                 return (DB_VERIFY_BAD);
02030         }
02031 
02032         /* Update the high-water mark (what HOFFSET should be) */
02033         if (offset < *himarkp)
02034                 *himarkp = offset;
02035 
02036         if (is_btree) {
02037                 /*
02038                  * Check alignment;  if it's unaligned, it's unsafe to
02039                  * manipulate this item.
02040                  */
02041                 if (offset != DB_ALIGN(offset, sizeof(u_int32_t))) {
02042                         EPRINT((dbenv,
02043                             "Page %lu: unaligned offset %lu at page index %lu",
02044                             (u_long)pgno, (u_long)offset, (u_long)i));
02045                         return (DB_VERIFY_BAD);
02046                 }
02047 
02048                 /*
02049                  * Check that the item length remains on-page.
02050                  */
02051                 bk = GET_BKEYDATA(dbp, h, i);
02052 
02053                 /*
02054                  * We need to verify the type of the item here;
02055                  * we can't simply assume that it will be one of the
02056                  * expected three.  If it's not a recognizable type,
02057                  * it can't be considered to have a verifiable
02058                  * length, so it's not possible to certify it as safe.
02059                  */
02060                 switch (B_TYPE(bk->type)) {
02061                 case B_KEYDATA:
02062                         len = bk->len;
02063                         break;
02064                 case B_DUPLICATE:
02065                 case B_OVERFLOW:
02066                         len = BOVERFLOW_SIZE;
02067                         break;
02068                 default:
02069                         EPRINT((dbenv,
02070                             "Page %lu: item %lu of unrecognizable type",
02071                             (u_long)pgno, (u_long)i));
02072                         return (DB_VERIFY_BAD);
02073                 }
02074 
02075                 if ((size_t)(offset + len) > dbp->pgsize) {
02076                         EPRINT((dbenv,
02077                             "Page %lu: item %lu extends past page boundary",
02078                             (u_long)pgno, (u_long)i));
02079                         return (DB_VERIFY_BAD);
02080                 }
02081         }
02082 
02083         if (offsetp != NULL)
02084                 *offsetp = offset;
02085         return (0);
02086 }
02087 
02088 /*
02089  * __db_vrfy_duptype--
02090  *      Given a page number and a set of flags to __bam_vrfy_subtree,
02091  *      verify that the dup tree type is correct--i.e., it's a recno
02092  *      if DUPSORT is not set and a btree if it is.
02093  *
02094  * PUBLIC: int __db_vrfy_duptype
02095  * PUBLIC:     __P((DB *, VRFY_DBINFO *, db_pgno_t, u_int32_t));
02096  */
02097 int
02098 __db_vrfy_duptype(dbp, vdp, pgno, flags)
02099         DB *dbp;
02100         VRFY_DBINFO *vdp;
02101         db_pgno_t pgno;
02102         u_int32_t flags;
02103 {
02104         DB_ENV *dbenv;
02105         VRFY_PAGEINFO *pip;
02106         int ret, isbad;
02107 
02108         dbenv = dbp->dbenv;
02109         isbad = 0;
02110 
02111         if ((ret = __db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0)
02112                 return (ret);
02113 
02114         switch (pip->type) {
02115         case P_IBTREE:
02116         case P_LDUP:
02117                 if (!LF_ISSET(ST_DUPSORT)) {
02118                         EPRINT((dbenv,
02119             "Page %lu: sorted duplicate set in unsorted-dup database",
02120                             (u_long)pgno));
02121                         isbad = 1;
02122                 }
02123                 break;
02124         case P_IRECNO:
02125         case P_LRECNO:
02126                 if (LF_ISSET(ST_DUPSORT)) {
02127                         EPRINT((dbenv,
02128             "Page %lu: unsorted duplicate set in sorted-dup database",
02129                             (u_long)pgno));
02130                         isbad = 1;
02131                 }
02132                 break;
02133         default:
02134                 /*
02135                  * If the page is entirely zeroed, its pip->type will be a lie
02136                  * (we assumed it was a hash page, as they're allowed to be
02137                  * zeroed);  handle this case specially.
02138                  */
02139                 if (F_ISSET(pip, VRFY_IS_ALLZEROES))
02140                         ZEROPG_ERR_PRINT(dbenv, pgno, "duplicate page");
02141                 else
02142                         EPRINT((dbenv,
02143                     "Page %lu: duplicate page of inappropriate type %lu",
02144                             (u_long)pgno, (u_long)pip->type));
02145                 isbad = 1;
02146                 break;
02147         }
02148 
02149         if ((ret = __db_vrfy_putpageinfo(dbenv, vdp, pip)) != 0)
02150                 return (ret);
02151         return (isbad == 1 ? DB_VERIFY_BAD : 0);
02152 }
02153 
02154 /*
02155  * __db_salvage_duptree --
02156  *      Attempt to salvage a given duplicate tree, given its alleged root.
02157  *
02158  *      The key that corresponds to this dup set has been passed to us
02159  *      in DBT *key.  Because data items follow keys, though, it has been
02160  *      printed once already.
02161  *
02162  *      The basic idea here is that pgno ought to be a P_LDUP, a P_LRECNO, a
02163  *      P_IBTREE, or a P_IRECNO.  If it's an internal page, use the verifier
02164  *      functions to make sure it's safe;  if it's not, we simply bail and the
02165  *      data will have to be printed with no key later on.  if it is safe,
02166  *      recurse on each of its children.
02167  *
02168  *      Whether or not it's safe, if it's a leaf page, __bam_salvage it.
02169  *
02170  *      At all times, use the DB hanging off vdp to mark and check what we've
02171  *      done, so each page gets printed exactly once and we don't get caught
02172  *      in any cycles.
02173  *
02174  * PUBLIC: int __db_salvage_duptree __P((DB *, VRFY_DBINFO *, db_pgno_t,
02175  * PUBLIC:     DBT *, void *, int (*)(void *, const void *), u_int32_t));
02176  */
02177 int
02178 __db_salvage_duptree(dbp, vdp, pgno, key, handle, callback, flags)
02179         DB *dbp;
02180         VRFY_DBINFO *vdp;
02181         db_pgno_t pgno;
02182         DBT *key;
02183         void *handle;
02184         int (*callback) __P((void *, const void *));
02185         u_int32_t flags;
02186 {
02187         DB_MPOOLFILE *mpf;
02188         PAGE *h;
02189         int ret, t_ret;
02190 
02191         mpf = dbp->mpf;
02192 
02193         if (pgno == PGNO_INVALID || !IS_VALID_PGNO(pgno))
02194                 return (DB_VERIFY_BAD);
02195 
02196         /* We have a plausible page.  Try it. */
02197         if ((ret = __memp_fget(mpf, &pgno, 0, &h)) != 0)
02198                 return (ret);
02199 
02200         switch (TYPE(h)) {
02201         case P_IBTREE:
02202         case P_IRECNO:
02203                 if ((ret = __db_vrfy_common(dbp, vdp, h, pgno, flags)) != 0)
02204                         goto err;
02205                 if ((ret = __bam_vrfy(dbp,
02206                     vdp, h, pgno, flags | DB_NOORDERCHK)) != 0 ||
02207                     (ret = __db_salvage_markdone(vdp, pgno)) != 0)
02208                         goto err;
02209                 /*
02210                  * We have a known-healthy internal page.  Walk it.
02211                  */
02212                 if ((ret = __bam_salvage_walkdupint(dbp, vdp, h, key,
02213                     handle, callback, flags)) != 0)
02214                         goto err;
02215                 break;
02216         case P_LRECNO:
02217         case P_LDUP:
02218                 if ((ret = __bam_salvage(dbp,
02219                     vdp, pgno, TYPE(h), h, handle, callback, key, flags)) != 0)
02220                         goto err;
02221                 break;
02222         default:
02223                 ret = DB_VERIFY_BAD;
02224                 goto err;
02225         }
02226 
02227 err:    if ((t_ret = __memp_fput(mpf, h, 0)) != 0 && ret == 0)
02228                 ret = t_ret;
02229         return (ret);
02230 }
02231 
02232 /*
02233  * __db_salvage_subdbs --
02234  *      Check and see if this database has subdbs;  if so, try to salvage
02235  *      them independently.
02236  */
02237 static int
02238 __db_salvage_subdbs(dbp, vdp, handle, callback, flags, hassubsp)
02239         DB *dbp;
02240         VRFY_DBINFO *vdp;
02241         void *handle;
02242         int (*callback) __P((void *, const void *));
02243         u_int32_t flags;
02244         int *hassubsp;
02245 {
02246         DB *pgset;
02247         DBC *pgsc;
02248         DB_ENV *dbenv;
02249         DB_MPOOLFILE *mpf;
02250         PAGE *h;
02251         VRFY_PAGEINFO *pip;
02252         db_pgno_t p, meta_pgno;
02253         int ret, t_ret;
02254 
02255         *hassubsp = 0;
02256 
02257         dbenv = dbp->dbenv;
02258         pgset = NULL;
02259         pgsc = NULL;
02260         mpf = dbp->mpf;
02261         h = NULL;
02262         pip = NULL;
02263         ret = 0;
02264 
02265         /*
02266          * Check to make sure the page is OK and find out if it contains
02267          * subdatabases.
02268          */
02269         meta_pgno = PGNO_BASE_MD;
02270         if ((t_ret = __memp_fget(mpf, &meta_pgno, 0, &h)) == 0 &&
02271             (t_ret = __db_vrfy_common(dbp, vdp, h, PGNO_BASE_MD, flags)) == 0 &&
02272             (t_ret = __db_salvage(
02273             dbp, vdp, PGNO_BASE_MD, h, handle, callback, flags)) == 0 &&
02274             (t_ret = __db_vrfy_getpageinfo(vdp, 0, &pip)) == 0)
02275                 if (F_ISSET(pip, VRFY_HAS_SUBDBS))
02276                         *hassubsp = 1;
02277         if (pip != NULL &&
02278             (t_ret = __db_vrfy_putpageinfo(dbenv, vdp, pip)) != 0 && ret == 0)
02279                 ret = t_ret;
02280         if (h != NULL) {
02281                 if ((t_ret = __memp_fput(mpf, h, 0)) != 0 && ret == 0)
02282                         ret = t_ret;
02283                 h = NULL;
02284         }
02285         if (ret != 0 || *hassubsp == 0)
02286                 return (ret);
02287 
02288         /*
02289          * We have subdbs.  Try to crack them.
02290          *
02291          * To do so, get a set of leaf pages in the master database, and then
02292          * walk each of the valid ones, salvaging subdbs as we go.  If any
02293          * prove invalid, just drop them;  we'll pick them up on a later pass.
02294          */
02295         if ((ret = __db_vrfy_pgset(dbenv, dbp->pgsize, &pgset)) != 0)
02296                 goto err;
02297         if ((ret = __db_meta2pgset(dbp, vdp, PGNO_BASE_MD, flags, pgset)) != 0)
02298                 goto err;
02299         if ((ret = __db_cursor(pgset, NULL, &pgsc, 0)) != 0)
02300                 goto err;
02301         while ((t_ret = __db_vrfy_pgset_next(pgsc, &p)) == 0) {
02302                 if ((t_ret = __memp_fget(mpf, &p, 0, &h)) == 0 &&
02303                     (t_ret = __db_vrfy_common(dbp, vdp, h, p, flags)) == 0 &&
02304                     (t_ret =
02305                     __bam_vrfy(dbp, vdp, h, p, flags | DB_NOORDERCHK)) == 0)
02306                         t_ret = __db_salvage_subdbpg(
02307                             dbp, vdp, h, handle, callback, flags);
02308                 if (t_ret != 0 && ret == 0)
02309                         ret = t_ret;
02310                 if (h != NULL) {
02311                         if ((t_ret = __memp_fput(mpf, h, 0)) != 0 && ret == 0)
02312                                 ret = t_ret;
02313                         h = NULL;
02314                 }
02315         }
02316 
02317         if (t_ret != DB_NOTFOUND && ret == 0)
02318                 ret = t_ret;
02319 
02320 err:    if (pgsc != NULL && (t_ret = __db_c_close(pgsc)) != 0 && ret == 0)
02321                 ret = t_ret;
02322         if (pgset != NULL &&
02323             (t_ret = __db_close(pgset, NULL, 0)) != 0 && ret ==0)
02324                 ret = t_ret;
02325         if (h != NULL && (t_ret = __memp_fput(mpf, h, 0)) != 0 && ret == 0)
02326                 ret = t_ret;
02327         return (ret);
02328 }
02329 
02330 /*
02331  * __db_salvage_subdbpg --
02332  *      Given a known-good leaf page in the master database, salvage all
02333  *      leaf pages corresponding to each subdb.
02334  */
02335 static int
02336 __db_salvage_subdbpg(dbp, vdp, master, handle, callback, flags)
02337         DB *dbp;
02338         VRFY_DBINFO *vdp;
02339         PAGE *master;
02340         void *handle;
02341         int (*callback) __P((void *, const void *));
02342         u_int32_t flags;
02343 {
02344         BKEYDATA *bkkey, *bkdata;
02345         BOVERFLOW *bo;
02346         DB *pgset;
02347         DBC *pgsc;
02348         DBT key;
02349         DB_ENV *dbenv;
02350         DB_MPOOLFILE *mpf;
02351         PAGE *subpg;
02352         db_indx_t i;
02353         db_pgno_t meta_pgno, p;
02354         int ret, err_ret, t_ret;
02355         char *subdbname;
02356 
02357         dbenv = dbp->dbenv;
02358         mpf = dbp->mpf;
02359         ret = err_ret = 0;
02360         subdbname = NULL;
02361 
02362         if ((ret = __db_vrfy_pgset(dbenv, dbp->pgsize, &pgset)) != 0)
02363                 return (ret);
02364 
02365         /*
02366          * For each entry, get and salvage the set of pages
02367          * corresponding to that entry.
02368          */
02369         for (i = 0; i < NUM_ENT(master); i += P_INDX) {
02370                 bkkey = GET_BKEYDATA(dbp, master, i);
02371                 bkdata = GET_BKEYDATA(dbp, master, i + O_INDX);
02372 
02373                 /* Get the subdatabase name. */
02374                 if (B_TYPE(bkkey->type) == B_OVERFLOW) {
02375                         /*
02376                          * We can, in principle anyway, have a subdb
02377                          * name so long it overflows.  Ick.
02378                          */
02379                         bo = (BOVERFLOW *)bkkey;
02380                         if ((ret = __db_safe_goff(dbp, vdp,
02381                             bo->pgno, &key, &subdbname, flags)) != 0) {
02382                                 err_ret = DB_VERIFY_BAD;
02383                                 continue;
02384                         }
02385 
02386                         /* Nul-terminate it. */
02387                         if ((ret = __os_realloc(dbenv,
02388                             key.size + 1, &subdbname)) != 0)
02389                                 goto err;
02390                         subdbname[key.size] = '\0';
02391                 } else if (B_TYPE(bkkey->type) == B_KEYDATA) {
02392                         if ((ret = __os_realloc(dbenv,
02393                             bkkey->len + 1, &subdbname)) != 0)
02394                                 goto err;
02395                         memcpy(subdbname, bkkey->data, bkkey->len);
02396                         subdbname[bkkey->len] = '\0';
02397                 }
02398 
02399                 /* Get the corresponding pgno. */
02400                 if (bkdata->len != sizeof(db_pgno_t)) {
02401                         err_ret = DB_VERIFY_BAD;
02402                         continue;
02403                 }
02404                 memcpy(&meta_pgno,
02405                     (db_pgno_t *)bkdata->data, sizeof(db_pgno_t));
02406 
02407                 /*
02408                  * Subdatabase meta pgnos are stored in network byte
02409                  * order for cross-endian compatibility.  Swap if appropriate.
02410                  */
02411                 DB_NTOHL(&meta_pgno);
02412 
02413                 /* If we can't get the subdb meta page, just skip the subdb. */
02414                 if (!IS_VALID_PGNO(meta_pgno) ||
02415                     (ret = __memp_fget(mpf, &meta_pgno, 0, &subpg)) != 0) {
02416                         err_ret = ret;
02417                         continue;
02418                 }
02419 
02420                 /*
02421                  * Verify the subdatabase meta page.  This has two functions.
02422                  * First, if it's bad, we have no choice but to skip the subdb
02423                  * and let the pages just get printed on a later pass.  Second,
02424                  * the access-method-specific meta verification routines record
02425                  * the various state info (such as the presence of dups)
02426                  * that we need for __db_prheader().
02427                  */
02428                 if ((ret =
02429                     __db_vrfy_common(dbp, vdp, subpg, meta_pgno, flags)) != 0) {
02430                         err_ret = ret;
02431                         (void)__memp_fput(mpf, subpg, 0);
02432                         continue;
02433                 }
02434                 switch (TYPE(subpg)) {
02435                 case P_BTREEMETA:
02436                         if ((ret = __bam_vrfy_meta(dbp,
02437                             vdp, (BTMETA *)subpg, meta_pgno, flags)) != 0) {
02438                                 err_ret = ret;
02439                                 (void)__memp_fput(mpf, subpg, 0);
02440                                 continue;
02441                         }
02442                         break;
02443                 case P_HASHMETA:
02444                         if ((ret = __ham_vrfy_meta(dbp,
02445                             vdp, (HMETA *)subpg, meta_pgno, flags)) != 0) {
02446                                 err_ret = ret;
02447                                 (void)__memp_fput(mpf, subpg, 0);
02448                                 continue;
02449                         }
02450                         break;
02451                 default:
02452                         /* This isn't an appropriate page;  skip this subdb. */
02453                         err_ret = DB_VERIFY_BAD;
02454                         continue;
02455                 }
02456 
02457                 if ((ret = __memp_fput(mpf, subpg, 0)) != 0) {
02458                         err_ret = ret;
02459                         continue;
02460                 }
02461 
02462                 /* Print a subdatabase header. */
02463                 if ((ret = __db_prheader(dbp,
02464                     subdbname, 0, 0, handle, callback, vdp, meta_pgno)) != 0)
02465                         goto err;
02466 
02467                 if ((ret = __db_meta2pgset(dbp, vdp, meta_pgno,
02468                     flags, pgset)) != 0) {
02469                         err_ret = ret;
02470                         continue;
02471                 }
02472 
02473                 if ((ret = __db_cursor(pgset, NULL, &pgsc, 0)) != 0)
02474                         goto err;
02475                 while ((ret = __db_vrfy_pgset_next(pgsc, &p)) == 0) {
02476                         if ((ret = __memp_fget(mpf, &p, 0, &subpg)) != 0) {
02477                                 err_ret = ret;
02478                                 continue;
02479                         }
02480                         if ((ret = __db_salvage(dbp, vdp, p, subpg,
02481                             handle, callback, flags)) != 0)
02482                                 err_ret = ret;
02483                         if ((ret = __memp_fput(mpf, subpg, 0)) != 0)
02484                                 err_ret = ret;
02485                 }
02486 
02487                 if (ret != DB_NOTFOUND)
02488                         goto err;
02489 
02490                 if ((ret = __db_c_close(pgsc)) != 0)
02491                         goto err;
02492                 if ((ret = __db_prfooter(handle, callback)) != 0)
02493                         goto err;
02494         }
02495 err:    if (subdbname)
02496                 __os_free(dbenv, subdbname);
02497 
02498         if ((t_ret = __db_close(pgset, NULL, 0)) != 0)
02499                 ret = t_ret;
02500 
02501         if ((t_ret = __db_salvage_markdone(vdp, PGNO(master))) != 0)
02502                 return (t_ret);
02503 
02504         return ((err_ret != 0) ? err_ret : ret);
02505 }
02506 
02507 /*
02508  * __db_meta2pgset --
02509  *      Given a known-safe meta page number, return the set of pages
02510  *      corresponding to the database it represents.  Return DB_VERIFY_BAD if
02511  *      it's not a suitable meta page or is invalid.
02512  */
02513 static int
02514 __db_meta2pgset(dbp, vdp, pgno, flags, pgset)
02515         DB *dbp;
02516         VRFY_DBINFO *vdp;
02517         db_pgno_t pgno;
02518         u_int32_t flags;
02519         DB *pgset;
02520 {
02521         DB_MPOOLFILE *mpf;
02522         PAGE *h;
02523         int ret, t_ret;
02524 
02525         mpf = dbp->mpf;
02526 
02527         if ((ret = __memp_fget(mpf, &pgno, 0, &h)) != 0)
02528                 return (ret);
02529 
02530         switch (TYPE(h)) {
02531         case P_BTREEMETA:
02532                 ret = __bam_meta2pgset(dbp, vdp, (BTMETA *)h, flags, pgset);
02533                 break;
02534         case P_HASHMETA:
02535                 ret = __ham_meta2pgset(dbp, vdp, (HMETA *)h, flags, pgset);
02536                 break;
02537         default:
02538                 ret = DB_VERIFY_BAD;
02539                 break;
02540         }
02541 
02542         if ((t_ret = __memp_fput(mpf, h, 0)) != 0)
02543                 return (t_ret);
02544         return (ret);
02545 }
02546 
02547 /*
02548  * __db_guesspgsize --
02549  *      Try to guess what the pagesize is if the one on the meta page
02550  *      and the one in the db are invalid.
02551  */
02552 static u_int
02553 __db_guesspgsize(dbenv, fhp)
02554         DB_ENV *dbenv;
02555         DB_FH *fhp;
02556 {
02557         db_pgno_t i;
02558         size_t nr;
02559         u_int32_t guess;
02560         u_int8_t type;
02561 
02562         for (guess = DB_MAX_PGSIZE; guess >= DB_MIN_PGSIZE; guess >>= 1) {
02563                 /*
02564                  * We try to read three pages ahead after the first one
02565                  * and make sure we have plausible types for all of them.
02566                  * If the seeks fail, continue with a smaller size;
02567                  * we're probably just looking past the end of the database.
02568                  * If they succeed and the types are reasonable, also continue
02569                  * with a size smaller;  we may be looking at pages N,
02570                  * 2N, and 3N for some N > 1.
02571                  *
02572                  * As soon as we hit an invalid type, we stop and return
02573                  * our previous guess; that last one was probably the page size.
02574                  */
02575                 for (i = 1; i <= 3; i++) {
02576                         if (__os_seek(dbenv, fhp, guess,
02577                             i, SSZ(DBMETA, type), 0, DB_OS_SEEK_SET) != 0)
02578                                 break;
02579                         if (__os_read(dbenv,
02580                             fhp, &type, 1, &nr) != 0 || nr == 0)
02581                                 break;
02582                         if (type == P_INVALID || type >= P_PAGETYPE_MAX)
02583                                 return (guess << 1);
02584                 }
02585         }
02586 
02587         /*
02588          * If we're just totally confused--the corruption takes up most of the
02589          * beginning pages of the database--go with the default size.
02590          */
02591         return (DB_DEF_IOSIZE);
02592 }

Generated on Sun Dec 25 12:14:22 2005 for Berkeley DB 4.4.16 by  doxygen 1.4.2