db_vrfy.c
上传用户:romrleung
上传日期:2022-05-23
资源大小:18897k
文件大小:62k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /*-
  2.  * See the file LICENSE for redistribution information.
  3.  *
  4.  * Copyright (c) 2000-2002
  5.  * Sleepycat Software.  All rights reserved.
  6.  *
  7.  * $Id: db_vrfy.c,v 1.107 2002/09/03 17:27:15 bostic Exp $
  8.  */
  9. #include "db_config.h"
  10. #ifndef lint
  11. static const char revid[] = "$Id: db_vrfy.c,v 1.107 2002/09/03 17:27:15 bostic Exp $";
  12. #endif /* not lint */
  13. #ifndef NO_SYSTEM_INCLUDES
  14. #include <sys/types.h>
  15. #include <string.h>
  16. #endif
  17. #include "db_int.h"
  18. #include "dbinc/db_page.h"
  19. #include "dbinc/db_shash.h"
  20. #include "dbinc/db_swap.h"
  21. #include "dbinc/db_verify.h"
  22. #include "dbinc/btree.h"
  23. #include "dbinc/hash.h"
  24. #include "dbinc/lock.h"
  25. #include "dbinc/qam.h"
  26. #include "dbinc/txn.h"
  27. static int  __db_guesspgsize __P((DB_ENV *, DB_FH *));
  28. static int  __db_is_valid_magicno __P((u_int32_t, DBTYPE *));
  29. static int  __db_is_valid_pagetype __P((u_int32_t));
  30. static int  __db_meta2pgset
  31. __P((DB *, VRFY_DBINFO *, db_pgno_t, u_int32_t, DB *));
  32. static int __db_salvage __P((DB *, VRFY_DBINFO *, db_pgno_t,
  33. PAGE *, void *, int (*)(void *, const void *), u_int32_t));
  34. static int __db_salvage_subdbpg __P((DB *, VRFY_DBINFO *,
  35. PAGE *, void *, int (*)(void *, const void *), u_int32_t));
  36. static int  __db_salvage_subdbs
  37. __P((DB *, VRFY_DBINFO *, void *,
  38. int(*)(void *, const void *), u_int32_t, int *));
  39. static int  __db_salvage_unknowns
  40. __P((DB *, VRFY_DBINFO *, void *,
  41. int (*)(void *, const void *), u_int32_t));
  42. static int  __db_vrfy_common
  43. __P((DB *, VRFY_DBINFO *, PAGE *, db_pgno_t, u_int32_t));
  44. static int  __db_vrfy_freelist __P((DB *, VRFY_DBINFO *, db_pgno_t, u_int32_t));
  45. static int  __db_vrfy_invalid
  46. __P((DB *, VRFY_DBINFO *, PAGE *, db_pgno_t, u_int32_t));
  47. static int  __db_vrfy_orderchkonly __P((DB *,
  48. VRFY_DBINFO *, const char *, const char *, u_int32_t));
  49. static int  __db_vrfy_pagezero __P((DB *, VRFY_DBINFO *, DB_FH *, u_int32_t));
  50. static int  __db_vrfy_subdbs
  51. __P((DB *, VRFY_DBINFO *, const char *, u_int32_t));
  52. static int  __db_vrfy_structure
  53. __P((DB *, VRFY_DBINFO *, const char *, db_pgno_t, u_int32_t));
  54. static int  __db_vrfy_walkpages
  55. __P((DB *, VRFY_DBINFO *, void *, int (*)(void *, const void *),
  56. u_int32_t));
  57. /*
  58.  * This is the code for DB->verify, the DB database consistency checker.
  59.  * For now, it checks all subdatabases in a database, and verifies
  60.  * everything it knows how to (i.e. it's all-or-nothing, and one can't
  61.  * check only for a subset of possible problems).
  62.  */
  63. /*
  64.  * __db_verify --
  65.  * Walk the entire file page-by-page, either verifying with or without
  66.  * dumping in db_dump -d format, or DB_SALVAGE-ing whatever key/data
  67.  * pairs can be found and dumping them in standard (db_load-ready)
  68.  * dump format.
  69.  *
  70.  * (Salvaging isn't really a verification operation, but we put it
  71.  * here anyway because it requires essentially identical top-level
  72.  * code.)
  73.  *
  74.  * flags may be 0, DB_NOORDERCHK, DB_ORDERCHKONLY, or DB_SALVAGE
  75.  * (and optionally DB_AGGRESSIVE).
  76.  *
  77.  * __db_verify itself is simply a wrapper to __db_verify_internal,
  78.  * which lets us pass appropriate equivalents to FILE * in from the
  79.  * non-C APIs.
  80.  *
  81.  * PUBLIC: int __db_verify
  82.  * PUBLIC:     __P((DB *, const char *, const char *, FILE *, u_int32_t));
  83.  */
  84. int
  85. __db_verify(dbp, file, database, outfile, flags)
  86. DB *dbp;
  87. const char *file, *database;
  88. FILE *outfile;
  89. u_int32_t flags;
  90. {
  91. return (__db_verify_internal(dbp,
  92.     file, database, outfile, __db_verify_callback, flags));
  93. }
  94. /*
  95.  * __db_verify_callback --
  96.  * Callback function for using pr_* functions from C.
  97.  *
  98.  * PUBLIC: int  __db_verify_callback __P((void *, const void *));
  99.  */
  100. int
  101. __db_verify_callback(handle, str_arg)
  102. void *handle;
  103. const void *str_arg;
  104. {
  105. char *str;
  106. FILE *f;
  107. str = (char *)str_arg;
  108. f = (FILE *)handle;
  109. if (fprintf(f, "%s", str) != (int)strlen(str))
  110. return (EIO);
  111. return (0);
  112. }
  113. /*
  114.  * __db_verify_internal --
  115.  * Inner meat of __db_verify.
  116.  *
  117.  * PUBLIC: int __db_verify_internal __P((DB *, const char *,
  118.  * PUBLIC:     const char *, void *, int (*)(void *, const void *), u_int32_t));
  119.  */
  120. int
  121. __db_verify_internal(dbp_orig, name, subdb, handle, callback, flags)
  122. DB *dbp_orig;
  123. const char *name, *subdb;
  124. void *handle;
  125. int (*callback) __P((void *, const void *));
  126. u_int32_t flags;
  127. {
  128. DB *dbp;
  129. DB_ENV *dbenv;
  130. DB_FH fh, *fhp;
  131. VRFY_DBINFO *vdp;
  132. int has, ret, isbad;
  133. char *real_name;
  134. dbenv = dbp_orig->dbenv;
  135. vdp = NULL;
  136. real_name = NULL;
  137. ret = isbad = 0;
  138. memset(&fh, 0, sizeof(fh));
  139. fhp = &fh;
  140. PANIC_CHECK(dbenv);
  141. DB_ILLEGAL_AFTER_OPEN(dbp_orig, "verify");
  142. #define OKFLAGS (DB_AGGRESSIVE | DB_NOORDERCHK | DB_ORDERCHKONLY | 
  143.     DB_PRINTABLE | DB_SALVAGE)
  144. if ((ret = __db_fchk(dbenv, "DB->verify", flags, OKFLAGS)) != 0)
  145. return (ret);
  146. /*
  147.  * DB_SALVAGE is mutually exclusive with the other flags except
  148.  * DB_AGGRESSIVE and DB_PRINTABLE.
  149.  */
  150. if (LF_ISSET(DB_SALVAGE) &&
  151.     (flags & ~DB_AGGRESSIVE & ~DB_PRINTABLE) != DB_SALVAGE)
  152. return (__db_ferr(dbenv, "__db_verify", 1));
  153. /* DB_AGGRESSIVE and DB_PRINTABLE are only meaningful when salvaging. */
  154. if ((LF_ISSET(DB_AGGRESSIVE) || LF_ISSET(DB_PRINTABLE)) &&
  155.     !LF_ISSET(DB_SALVAGE))
  156. return (__db_ferr(dbenv, "__db_verify", 1));
  157. if (LF_ISSET(DB_ORDERCHKONLY) && flags != DB_ORDERCHKONLY)
  158. return (__db_ferr(dbenv, "__db_verify", 1));
  159. if (LF_ISSET(DB_ORDERCHKONLY) && subdb == NULL) {
  160. __db_err(dbenv, "DB_ORDERCHKONLY requires a database name");
  161. return (EINVAL);
  162. }
  163. /*
  164.  * Forbid working in an environment that uses transactions or
  165.  * locking;  we're going to be looking at the file freely,
  166.  * and while we're not going to modify it, we aren't obeying
  167.  * locking conventions either.
  168.  */
  169. if (TXN_ON(dbenv) || LOCKING_ON(dbenv) || LOGGING_ON(dbenv)) {
  170. dbp_orig->errx(dbp_orig,
  171.     "verify may not be used with transactions, logging, or locking");
  172. return (EINVAL);
  173. /* NOTREACHED */
  174. }
  175. /* Create a dbp to use internally, which we can close at our leisure. */
  176. if ((ret = db_create(&dbp, dbenv, 0)) != 0)
  177. goto err;
  178. F_SET(dbp, DB_AM_VERIFYING);
  179. /* Copy the supplied pagesize, which we use if the file one is bogus. */
  180. if (dbp_orig->pgsize >= DB_MIN_PGSIZE &&
  181.     dbp_orig->pgsize <= DB_MAX_PGSIZE)
  182. dbp->set_pagesize(dbp, dbp_orig->pgsize);
  183. /* Copy the feedback function, if present, and initialize it. */
  184. if (!LF_ISSET(DB_SALVAGE) && dbp_orig->db_feedback != NULL) {
  185. dbp->set_feedback(dbp, dbp_orig->db_feedback);
  186. dbp->db_feedback(dbp, DB_VERIFY, 0);
  187. }
  188. /*
  189.  * Copy the comparison and hashing functions.  Note that
  190.  * even if the database is not a hash or btree, the respective
  191.  * internal structures will have been initialized.
  192.  */
  193. if (dbp_orig->dup_compare != NULL &&
  194.     (ret = dbp->set_dup_compare(dbp, dbp_orig->dup_compare)) != 0)
  195. goto err;
  196. if (((BTREE *)dbp_orig->bt_internal)->bt_compare != NULL &&
  197.     (ret = dbp->set_bt_compare(dbp,
  198.     ((BTREE *)dbp_orig->bt_internal)->bt_compare)) != 0)
  199. goto err;
  200. if (((HASH *)dbp_orig->h_internal)->h_hash != NULL &&
  201.     (ret = dbp->set_h_hash(dbp,
  202.     ((HASH *)dbp_orig->h_internal)->h_hash)) != 0)
  203. goto err;
  204. /*
  205.  * We don't know how large the cache is, and if the database
  206.  * in question uses a small page size--which we don't know
  207.  * yet!--it may be uncomfortably small for the default page
  208.  * size [#2143].  However, the things we need temporary
  209.  * databases for in dbinfo are largely tiny, so using a
  210.  * 1024-byte pagesize is probably not going to be a big hit,
  211.  * and will make us fit better into small spaces.
  212.  */
  213. if ((ret = __db_vrfy_dbinfo_create(dbenv, 1024, &vdp)) != 0)
  214. goto err;
  215. /*
  216.  * Note whether the user has requested that we use printable
  217.  * chars where possible.  We won't get here with this flag if
  218.  * we're not salvaging.
  219.  */
  220. if (LF_ISSET(DB_PRINTABLE))
  221. F_SET(vdp, SALVAGE_PRINTABLE);
  222. /* Find the real name of the file. */
  223. if ((ret = __db_appname(dbenv,
  224.     DB_APP_DATA, name, 0, NULL, &real_name)) != 0)
  225. goto err;
  226. /*
  227.  * Our first order of business is to verify page 0, which is
  228.  * the metadata page for the master database of subdatabases
  229.  * or of the only database in the file.  We want to do this by hand
  230.  * rather than just calling __db_open in case it's corrupt--various
  231.  * things in __db_open might act funny.
  232.  *
  233.  * Once we know the metadata page is healthy, I believe that it's
  234.  * safe to open the database normally and then use the page swapping
  235.  * code, which makes life easier.
  236.  */
  237. if ((ret = __os_open(dbenv, real_name, DB_OSO_RDONLY, 0444, fhp)) != 0)
  238. goto err;
  239. /* Verify the metadata page 0; set pagesize and type. */
  240. if ((ret = __db_vrfy_pagezero(dbp, vdp, fhp, flags)) != 0) {
  241. if (ret == DB_VERIFY_BAD)
  242. isbad = 1;
  243. else
  244. goto err;
  245. }
  246. /*
  247.  * We can assume at this point that dbp->pagesize and dbp->type are
  248.  * set correctly, or at least as well as they can be, and that
  249.  * locking, logging, and txns are not in use.  Thus we can trust
  250.  * the memp code not to look at the page, and thus to be safe
  251.  * enough to use.
  252.  *
  253.  * The dbp is not open, but the file is open in the fhp, and we
  254.  * cannot assume that __db_open is safe.  Call __db_dbenv_setup,
  255.  * the [safe] part of __db_open that initializes the environment--
  256.  * and the mpool--manually.
  257.  */
  258. if ((ret = __db_dbenv_setup(dbp, NULL,
  259.     name, TXN_INVALID, DB_ODDFILESIZE | DB_RDONLY)) != 0)
  260. return (ret);
  261. /* Mark the dbp as opened, so that we correctly handle its close. */
  262. F_SET(dbp, DB_AM_OPEN_CALLED);
  263. /* Find out the page number of the last page in the database. */
  264. dbp->mpf->last_pgno(dbp->mpf, &vdp->last_pgno);
  265. /*
  266.  * DB_ORDERCHKONLY is a special case;  our file consists of
  267.  * several subdatabases, which use different hash, bt_compare,
  268.  * and/or dup_compare functions.  Consequently, we couldn't verify
  269.  * sorting and hashing simply by calling DB->verify() on the file.
  270.  * DB_ORDERCHKONLY allows us to come back and check those things;  it
  271.  * requires a subdatabase, and assumes that everything but that
  272.  * database's sorting/hashing is correct.
  273.  */
  274. if (LF_ISSET(DB_ORDERCHKONLY)) {
  275. ret = __db_vrfy_orderchkonly(dbp, vdp, name, subdb, flags);
  276. goto done;
  277. }
  278. /*
  279.  * When salvaging, we use a db to keep track of whether we've seen a
  280.  * given overflow or dup page in the course of traversing normal data.
  281.  * If in the end we have not, we assume its key got lost and print it
  282.  * with key "UNKNOWN".
  283.  */
  284. if (LF_ISSET(DB_SALVAGE)) {
  285. if ((ret = __db_salvage_init(vdp)) != 0)
  286. return (ret);
  287. /*
  288.  * If we're not being aggressive, attempt to crack subdbs.
  289.  * "has" will indicate whether the attempt has succeeded
  290.  * (even in part), meaning that we have some semblance of
  291.  * subdbs;  on the walkpages pass, we print out
  292.  * whichever data pages we have not seen.
  293.  */
  294. has = 0;
  295. if (!LF_ISSET(DB_AGGRESSIVE) && (__db_salvage_subdbs(dbp,
  296.     vdp, handle, callback, flags, &has)) != 0)
  297. isbad = 1;
  298. /*
  299.  * If we have subdatabases, we need to signal that if
  300.  * any keys are found that don't belong to a subdatabase,
  301.  * they'll need to have an "__OTHER__" subdatabase header
  302.  * printed first.  Flag this.  Else, print a header for
  303.  * the normal, non-subdb database.
  304.  */
  305. if (has == 1)
  306. F_SET(vdp, SALVAGE_PRINTHEADER);
  307. else if ((ret = __db_prheader(dbp,
  308.     NULL, 0, 0, handle, callback, vdp, PGNO_BASE_MD)) != 0)
  309. goto err;
  310. }
  311. if ((ret =
  312.     __db_vrfy_walkpages(dbp, vdp, handle, callback, flags)) != 0) {
  313. if (ret == DB_VERIFY_BAD)
  314. isbad = 1;
  315. else if (ret != 0)
  316. goto err;
  317. }
  318. /* If we're verifying, verify inter-page structure. */
  319. if (!LF_ISSET(DB_SALVAGE) && isbad == 0)
  320. if ((ret =
  321.     __db_vrfy_structure(dbp, vdp, name, 0, flags)) != 0) {
  322. if (ret == DB_VERIFY_BAD)
  323. isbad = 1;
  324. else if (ret != 0)
  325. goto err;
  326. }
  327. /*
  328.  * If we're salvaging, output with key UNKNOWN any overflow or dup pages
  329.  * we haven't been able to put in context.  Then destroy the salvager's
  330.  * state-saving database.
  331.  */
  332. if (LF_ISSET(DB_SALVAGE)) {
  333. if ((ret = __db_salvage_unknowns(dbp,
  334.     vdp, handle, callback, flags)) != 0)
  335. isbad = 1;
  336. /* No return value, since there's little we can do. */
  337. __db_salvage_destroy(vdp);
  338. }
  339. if (0) {
  340. /* Don't try to strerror() DB_VERIFY_FATAL;  it's private. */
  341. err: if (ret == DB_VERIFY_FATAL)
  342. ret = DB_VERIFY_BAD;
  343. (void)__db_err(dbenv, "%s: %s", name, db_strerror(ret));
  344. }
  345. if (LF_ISSET(DB_SALVAGE) &&
  346.     (has == 0 || F_ISSET(vdp, SALVAGE_PRINTFOOTER)))
  347. (void)__db_prfooter(handle, callback);
  348. /* Send feedback that we're done. */
  349. done: if (!LF_ISSET(DB_SALVAGE) && dbp->db_feedback != NULL)
  350. dbp->db_feedback(dbp, DB_VERIFY, 100);
  351. if (F_ISSET(fhp, DB_FH_VALID))
  352. (void)__os_closehandle(dbenv, fhp);
  353. if (dbp)
  354. (void)dbp->close(dbp, 0);
  355. if (vdp)
  356. (void)__db_vrfy_dbinfo_destroy(dbenv, vdp);
  357. if (real_name)
  358. __os_free(dbenv, real_name);
  359. if ((ret == 0 && isbad == 1) || ret == DB_VERIFY_FATAL)
  360. ret = DB_VERIFY_BAD;
  361. return (ret);
  362. }
  363. /*
  364.  * __db_vrfy_pagezero --
  365.  * Verify the master metadata page.  Use seek, read, and a local buffer
  366.  * rather than the DB paging code, for safety.
  367.  *
  368.  * Must correctly (or best-guess) set dbp->type and dbp->pagesize.
  369.  */
  370. static int
  371. __db_vrfy_pagezero(dbp, vdp, fhp, flags)
  372. DB *dbp;
  373. VRFY_DBINFO *vdp;
  374. DB_FH *fhp;
  375. u_int32_t flags;
  376. {
  377. DBMETA *meta;
  378. DB_ENV *dbenv;
  379. VRFY_PAGEINFO *pip;
  380. db_pgno_t freelist;
  381. size_t nr;
  382. int isbad, ret, swapped;
  383. u_int8_t mbuf[DBMETASIZE];
  384. isbad = ret = swapped = 0;
  385. freelist = 0;
  386. dbenv = dbp->dbenv;
  387. meta = (DBMETA *)mbuf;
  388. dbp->type = DB_UNKNOWN;
  389. /*
  390.  * Seek to the metadata page.
  391.  * Note that if we're just starting a verification, dbp->pgsize
  392.  * may be zero;  this is okay, as we want page zero anyway and
  393.  * 0*0 == 0.
  394.  */
  395. if ((ret = __os_seek(dbenv, fhp, 0, 0, 0, 0, DB_OS_SEEK_SET)) != 0 ||
  396.     (ret = __os_read(dbenv, fhp, mbuf, DBMETASIZE, &nr)) != 0) {
  397. __db_err(dbenv,
  398.     "Metadata page %lu cannot be read: %s",
  399.     (u_long)PGNO_BASE_MD, db_strerror(ret));
  400. return (ret);
  401. }
  402. if (nr != DBMETASIZE) {
  403. EPRINT((dbenv,
  404.     "Page %lu: Incomplete metadata page",
  405.     (u_long)PGNO_BASE_MD));
  406. return (DB_VERIFY_FATAL);
  407. }
  408. if ((ret = __db_chk_meta(dbenv, dbp, meta, 1)) != 0) {
  409. EPRINT((dbenv,
  410.     "Page %lu: metadata page corrupted, (u_long)PGNO_BASE_MD"));
  411. isbad = 1;
  412. if (ret != -1) {
  413. EPRINT((dbenv,
  414.     "Page %lu: could not check metadata page",
  415.     (u_long)PGNO_BASE_MD));
  416. return (DB_VERIFY_FATAL);
  417. }
  418. }
  419. /*
  420.  * Check all of the fields that we can.
  421.  *
  422.  * 08-11: Current page number.  Must == pgno.
  423.  * Note that endianness doesn't matter--it's zero.
  424.  */
  425. if (meta->pgno != PGNO_BASE_MD) {
  426. isbad = 1;
  427. EPRINT((dbenv, "Page %lu: pgno incorrectly set to %lu",
  428.     (u_long)PGNO_BASE_MD, (u_long)meta->pgno));
  429. }
  430. /* 12-15: Magic number.  Must be one of valid set. */
  431. if (__db_is_valid_magicno(meta->magic, &dbp->type))
  432. swapped = 0;
  433. else {
  434. M_32_SWAP(meta->magic);
  435. if (__db_is_valid_magicno(meta->magic,
  436.     &dbp->type))
  437. swapped = 1;
  438. else {
  439. isbad = 1;
  440. EPRINT((dbenv,
  441.     "Page %lu: bad magic number %lu",
  442.     (u_long)PGNO_BASE_MD, (u_long)meta->magic));
  443. }
  444. }
  445. /*
  446.  * 16-19: Version.  Must be current;  for now, we
  447.  * don't support verification of old versions.
  448.  */
  449. if (swapped)
  450. M_32_SWAP(meta->version);
  451. if ((dbp->type == DB_BTREE &&
  452.     (meta->version > DB_BTREEVERSION ||
  453.     meta->version < DB_BTREEOLDVER)) ||
  454.     (dbp->type == DB_HASH &&
  455.     (meta->version > DB_HASHVERSION ||
  456.     meta->version < DB_HASHOLDVER)) ||
  457.     (dbp->type == DB_QUEUE &&
  458.     (meta->version > DB_QAMVERSION ||
  459.     meta->version < DB_QAMOLDVER))) {
  460. isbad = 1;
  461. EPRINT((dbenv,
  462.     "Page %lu: unsupported DB version %lu; extraneous errors may result",
  463.     (u_long)PGNO_BASE_MD, (u_long)meta->version));
  464. }
  465. /*
  466.  * 20-23: Pagesize.  Must be power of two,
  467.  * greater than 512, and less than 64K.
  468.  */
  469. if (swapped)
  470. M_32_SWAP(meta->pagesize);
  471. if (IS_VALID_PAGESIZE(meta->pagesize))
  472. dbp->pgsize = meta->pagesize;
  473. else {
  474. isbad = 1;
  475. EPRINT((dbenv, "Page %lu: bad page size %lu",
  476.     (u_long)PGNO_BASE_MD, (u_long)meta->pagesize));
  477. /*
  478.  * Now try to settle on a pagesize to use.
  479.  * If the user-supplied one is reasonable,
  480.  * use it;  else, guess.
  481.  */
  482. if (!IS_VALID_PAGESIZE(dbp->pgsize))
  483. dbp->pgsize = __db_guesspgsize(dbenv, fhp);
  484. }
  485. /*
  486.  * 25: Page type.  Must be correct for dbp->type,
  487.  * which is by now set as well as it can be.
  488.  */
  489. /* Needs no swapping--only one byte! */
  490. if ((dbp->type == DB_BTREE && meta->type != P_BTREEMETA) ||
  491.     (dbp->type == DB_HASH && meta->type != P_HASHMETA) ||
  492.     (dbp->type == DB_QUEUE && meta->type != P_QAMMETA)) {
  493. isbad = 1;
  494. EPRINT((dbenv, "Page %lu: bad page type %lu",
  495.     (u_long)PGNO_BASE_MD, (u_long)meta->type));
  496. }
  497. /*
  498.  * 28-31: Free list page number.
  499.  * We'll verify its sensibility when we do inter-page
  500.  * verification later;  for now, just store it.
  501.  */
  502. if (swapped)
  503.     M_32_SWAP(meta->free);
  504. freelist = meta->free;
  505. /*
  506.  * Initialize vdp->pages to fit a single pageinfo structure for
  507.  * this one page.  We'll realloc later when we know how many
  508.  * pages there are.
  509.  */
  510. if ((ret = __db_vrfy_getpageinfo(vdp, PGNO_BASE_MD, &pip)) != 0)
  511. return (ret);
  512. pip->pgno = PGNO_BASE_MD;
  513. pip->type = meta->type;
  514. /*
  515.  * Signal that we still have to check the info specific to
  516.  * a given type of meta page.
  517.  */
  518. F_SET(pip, VRFY_INCOMPLETE);
  519. pip->free = freelist;
  520. if ((ret = __db_vrfy_putpageinfo(dbenv, vdp, pip)) != 0)
  521. return (ret);
  522. /* Set up the dbp's fileid.  We don't use the regular open path. */
  523. memcpy(dbp->fileid, meta->uid, DB_FILE_ID_LEN);
  524. if (swapped == 1)
  525. F_SET(dbp, DB_AM_SWAP);
  526. return (isbad ? DB_VERIFY_BAD : 0);
  527. }
  528. /*
  529.  * __db_vrfy_walkpages --
  530.  * Main loop of the verifier/salvager.  Walks through,
  531.  * page by page, and verifies all pages and/or prints all data pages.
  532.  */
  533. static int
  534. __db_vrfy_walkpages(dbp, vdp, handle, callback, flags)
  535. DB *dbp;
  536. VRFY_DBINFO *vdp;
  537. void *handle;
  538. int (*callback) __P((void *, const void *));
  539. u_int32_t flags;
  540. {
  541. DB_ENV *dbenv;
  542. DB_MPOOLFILE *mpf;
  543. PAGE *h;
  544. db_pgno_t i;
  545. int ret, t_ret, isbad;
  546. dbenv = dbp->dbenv;
  547. mpf = dbp->mpf;
  548. ret = isbad = t_ret = 0;
  549. if ((ret = __db_fchk(dbenv,
  550.     "__db_vrfy_walkpages", flags, OKFLAGS)) != 0)
  551. return (ret);
  552. for (i = 0; i <= vdp->last_pgno; i++) {
  553. /*
  554.  * If DB_SALVAGE is set, we inspect our database of
  555.  * completed pages, and skip any we've already printed in
  556.  * the subdb pass.
  557.  */
  558. if (LF_ISSET(DB_SALVAGE) && (__db_salvage_isdone(vdp, i) != 0))
  559. continue;
  560. /*
  561.  * If an individual page get fails, keep going if and only
  562.  * if we're salvaging.
  563.  */
  564. if ((t_ret = mpf->get(mpf, &i, 0, &h)) != 0) {
  565. if (ret == 0)
  566. ret = t_ret;
  567. if (LF_ISSET(DB_SALVAGE))
  568. continue;
  569. else
  570. return (ret);
  571. }
  572. if (LF_ISSET(DB_SALVAGE)) {
  573. /*
  574.  * We pretty much don't want to quit unless a
  575.  * bomb hits.  May as well return that something
  576.  * was screwy, however.
  577.  */
  578. if ((t_ret = __db_salvage(dbp,
  579.     vdp, i, h, handle, callback, flags)) != 0) {
  580. if (ret == 0)
  581. ret = t_ret;
  582. isbad = 1;
  583. }
  584. } else {
  585. /*
  586.  * If we are not salvaging, and we get any error
  587.  * other than DB_VERIFY_BAD, return immediately;
  588.  * it may not be safe to proceed.  If we get
  589.  * DB_VERIFY_BAD, keep going;  listing more errors
  590.  * may make it easier to diagnose problems and
  591.  * determine the magnitude of the corruption.
  592.  */
  593. /*
  594.  * Verify info common to all page
  595.  * types.
  596.  */
  597. if (i != PGNO_BASE_MD) {
  598. ret = __db_vrfy_common(dbp, vdp, h, i, flags);
  599. if (ret == DB_VERIFY_BAD)
  600. isbad = 1;
  601. else if (ret != 0)
  602. goto err;
  603. }
  604. switch (TYPE(h)) {
  605. case P_INVALID:
  606. ret = __db_vrfy_invalid(dbp, vdp, h, i, flags);
  607. break;
  608. case __P_DUPLICATE:
  609. isbad = 1;
  610. EPRINT((dbenv,
  611.     "Page %lu: old-style duplicate page",
  612.     (u_long)i));
  613. break;
  614. case P_HASH:
  615. ret = __ham_vrfy(dbp,
  616.     vdp, h, i, flags);
  617. break;
  618. case P_IBTREE:
  619. case P_IRECNO:
  620. case P_LBTREE:
  621. case P_LDUP:
  622. ret = __bam_vrfy(dbp,
  623.     vdp, h, i, flags);
  624. break;
  625. case P_LRECNO:
  626. ret = __ram_vrfy_leaf(dbp,
  627.     vdp, h, i, flags);
  628. break;
  629. case P_OVERFLOW:
  630. ret = __db_vrfy_overflow(dbp,
  631.     vdp, h, i, flags);
  632. break;
  633. case P_HASHMETA:
  634. ret = __ham_vrfy_meta(dbp,
  635.     vdp, (HMETA *)h, i, flags);
  636. break;
  637. case P_BTREEMETA:
  638. ret = __bam_vrfy_meta(dbp,
  639.     vdp, (BTMETA *)h, i, flags);
  640. break;
  641. case P_QAMMETA:
  642. ret = __qam_vrfy_meta(dbp,
  643.     vdp, (QMETA *)h, i, flags);
  644. break;
  645. case P_QAMDATA:
  646. ret = __qam_vrfy_data(dbp,
  647.     vdp, (QPAGE *)h, i, flags);
  648. break;
  649. default:
  650. EPRINT((dbenv,
  651.     "Page %lu: unknown page type %lu",
  652.     (u_long)i, (u_long)TYPE(h)));
  653. isbad = 1;
  654. break;
  655. }
  656. /*
  657.  * Set up error return.
  658.  */
  659. if (ret == DB_VERIFY_BAD)
  660. isbad = 1;
  661. else if (ret != 0)
  662. goto err;
  663. /*
  664.  * Provide feedback to the application about our
  665.  * progress.  The range 0-50% comes from the fact
  666.  * that this is the first of two passes through the
  667.  * database (front-to-back, then top-to-bottom).
  668.  */
  669. if (dbp->db_feedback != NULL)
  670. dbp->db_feedback(dbp, DB_VERIFY,
  671.     (i + 1) * 50 / (vdp->last_pgno + 1));
  672. }
  673. /*
  674.  * Just as with the page get, bail if and only if we're
  675.  * not salvaging.
  676.  */
  677. if ((t_ret = mpf->put(mpf, h, 0)) != 0) {
  678. if (ret == 0)
  679. ret = t_ret;
  680. if (!LF_ISSET(DB_SALVAGE))
  681. return (ret);
  682. }
  683. }
  684. if (0) {
  685. err: if ((t_ret = mpf->put(mpf, h, 0)) != 0)
  686. return (ret == 0 ? t_ret : ret);
  687. }
  688. return ((isbad == 1 && ret == 0) ? DB_VERIFY_BAD : ret);
  689. }
  690. /*
  691.  * __db_vrfy_structure--
  692.  * After a beginning-to-end walk through the database has been
  693.  * completed, put together the information that has been collected
  694.  * to verify the overall database structure.
  695.  *
  696.  * Should only be called if we want to do a database verification,
  697.  * i.e. if DB_SALVAGE is not set.
  698.  */
  699. static int
  700. __db_vrfy_structure(dbp, vdp, dbname, meta_pgno, flags)
  701. DB *dbp;
  702. VRFY_DBINFO *vdp;
  703. const char *dbname;
  704. db_pgno_t meta_pgno;
  705. u_int32_t flags;
  706. {
  707. DB *pgset;
  708. DB_ENV *dbenv;
  709. VRFY_PAGEINFO *pip;
  710. db_pgno_t i;
  711. int ret, isbad, hassubs, p;
  712. isbad = 0;
  713. pip = NULL;
  714. dbenv = dbp->dbenv;
  715. pgset = vdp->pgset;
  716. if ((ret = __db_fchk(dbenv, "DB->verify", flags, OKFLAGS)) != 0)
  717. return (ret);
  718. if (LF_ISSET(DB_SALVAGE)) {
  719. __db_err(dbenv, "__db_vrfy_structure called with DB_SALVAGE");
  720. return (EINVAL);
  721. }
  722. /*
  723.  * Providing feedback here is tricky;  in most situations,
  724.  * we fetch each page one more time, but we do so in a top-down
  725.  * order that depends on the access method.  Worse, we do this
  726.  * recursively in btree, such that on any call where we're traversing
  727.  * a subtree we don't know where that subtree is in the whole database;
  728.  * worse still, any given database may be one of several subdbs.
  729.  *
  730.  * The solution is to decrement a counter vdp->pgs_remaining each time
  731.  * we verify (and call feedback on) a page.  We may over- or
  732.  * under-count, but the structure feedback function will ensure that we
  733.  * never give a percentage under 50 or over 100.  (The first pass
  734.  * covered the range 0-50%.)
  735.  */
  736. if (dbp->db_feedback != NULL)
  737. vdp->pgs_remaining = vdp->last_pgno + 1;
  738. /*
  739.  * Call the appropriate function to downwards-traverse the db type.
  740.  */
  741. switch(dbp->type) {
  742. case DB_BTREE:
  743. case DB_RECNO:
  744. if ((ret = __bam_vrfy_structure(dbp, vdp, 0, flags)) != 0) {
  745. if (ret == DB_VERIFY_BAD)
  746. isbad = 1;
  747. else
  748. goto err;
  749. }
  750. /*
  751.  * If we have subdatabases and we know that the database is,
  752.  * thus far, sound, it's safe to walk the tree of subdatabases.
  753.  * Do so, and verify the structure of the databases within.
  754.  */
  755. if ((ret = __db_vrfy_getpageinfo(vdp, 0, &pip)) != 0)
  756. goto err;
  757. hassubs = F_ISSET(pip, VRFY_HAS_SUBDBS) ? 1 : 0;
  758. if ((ret = __db_vrfy_putpageinfo(dbenv, vdp, pip)) != 0)
  759. goto err;
  760. if (isbad == 0 && hassubs)
  761. if ((ret =
  762.     __db_vrfy_subdbs(dbp, vdp, dbname, flags)) != 0) {
  763. if (ret == DB_VERIFY_BAD)
  764. isbad = 1;
  765. else
  766. goto err;
  767. }
  768. break;
  769. case DB_HASH:
  770. if ((ret = __ham_vrfy_structure(dbp, vdp, 0, flags)) != 0) {
  771. if (ret == DB_VERIFY_BAD)
  772. isbad = 1;
  773. else
  774. goto err;
  775. }
  776. break;
  777. case DB_QUEUE:
  778. if ((ret = __qam_vrfy_structure(dbp, vdp, flags)) != 0) {
  779. if (ret == DB_VERIFY_BAD)
  780. isbad = 1;
  781. }
  782. /*
  783.  * Queue pages may be unreferenced and totally zeroed, if
  784.  * they're empty;  queue doesn't have much structure, so
  785.  * this is unlikely to be wrong in any troublesome sense.
  786.  * Skip to "err".
  787.  */
  788. goto err;
  789. /* NOTREACHED */
  790. default:
  791. /* This should only happen if the verifier is somehow broken. */
  792. DB_ASSERT(0);
  793. ret = EINVAL;
  794. goto err;
  795. /* NOTREACHED */
  796. }
  797. /* Walk free list. */
  798. if ((ret =
  799.     __db_vrfy_freelist(dbp, vdp, meta_pgno, flags)) == DB_VERIFY_BAD)
  800. isbad = 1;
  801. /*
  802.  * If structure checks up until now have failed, it's likely that
  803.  * checking what pages have been missed will result in oodles of
  804.  * extraneous error messages being EPRINTed.  Skip to the end
  805.  * if this is the case;  we're going to be printing at least one
  806.  * error anyway, and probably all the more salient ones.
  807.  */
  808. if (ret != 0 || isbad == 1)
  809. goto err;
  810. /*
  811.  * Make sure no page has been missed and that no page is still marked
  812.  * "all zeroes" (only certain hash pages can be, and they're unmarked
  813.  * in __ham_vrfy_structure).
  814.  */
  815. for (i = 0; i < vdp->last_pgno + 1; i++) {
  816. if ((ret = __db_vrfy_getpageinfo(vdp, i, &pip)) != 0)
  817. goto err;
  818. if ((ret = __db_vrfy_pgset_get(pgset, i, &p)) != 0)
  819. goto err;
  820. if (p == 0) {
  821. EPRINT((dbenv,
  822.     "Page %lu: unreferenced page", (u_long)i));
  823. isbad = 1;
  824. }
  825. if (F_ISSET(pip, VRFY_IS_ALLZEROES)) {
  826. EPRINT((dbenv,
  827.     "Page %lu: totally zeroed page", (u_long)i));
  828. isbad = 1;
  829. }
  830. if ((ret = __db_vrfy_putpageinfo(dbenv, vdp, pip)) != 0)
  831. goto err;
  832. pip = NULL;
  833. }
  834. err: if (pip != NULL)
  835. (void)__db_vrfy_putpageinfo(dbenv, vdp, pip);
  836. return ((isbad == 1 && ret == 0) ? DB_VERIFY_BAD : ret);
  837. }
  838. /*
  839.  * __db_is_valid_pagetype
  840.  */
  841. static int
  842. __db_is_valid_pagetype(type)
  843. u_int32_t type;
  844. {
  845. switch (type) {
  846. case P_INVALID: /* Order matches ordinal value. */
  847. case P_HASH:
  848. case P_IBTREE:
  849. case P_IRECNO:
  850. case P_LBTREE:
  851. case P_LRECNO:
  852. case P_OVERFLOW:
  853. case P_HASHMETA:
  854. case P_BTREEMETA:
  855. case P_QAMMETA:
  856. case P_QAMDATA:
  857. case P_LDUP:
  858. return (1);
  859. }
  860. return (0);
  861. }
  862. /*
  863.  * __db_is_valid_magicno
  864.  */
  865. static int
  866. __db_is_valid_magicno(magic, typep)
  867. u_int32_t magic;
  868. DBTYPE *typep;
  869. {
  870. switch (magic) {
  871. case DB_BTREEMAGIC:
  872. *typep = DB_BTREE;
  873. return (1);
  874. case DB_HASHMAGIC:
  875. *typep = DB_HASH;
  876. return (1);
  877. case DB_QAMMAGIC:
  878. *typep = DB_QUEUE;
  879. return (1);
  880. }
  881. *typep = DB_UNKNOWN;
  882. return (0);
  883. }
  884. /*
  885.  * __db_vrfy_common --
  886.  * Verify info common to all page types.
  887.  */
  888. static int
  889. __db_vrfy_common(dbp, vdp, h, pgno, flags)
  890. DB *dbp;
  891. VRFY_DBINFO *vdp;
  892. PAGE *h;
  893. db_pgno_t pgno;
  894. u_int32_t flags;
  895. {
  896. DB_ENV *dbenv;
  897. VRFY_PAGEINFO *pip;
  898. int ret, t_ret;
  899. u_int8_t *p;
  900. dbenv = dbp->dbenv;
  901. if ((ret = __db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0)
  902. return (ret);
  903. pip->pgno = pgno;
  904. F_CLR(pip, VRFY_IS_ALLZEROES);
  905. /*
  906.  * Hash expands the table by leaving some pages between the
  907.  * old last and the new last totally zeroed.  Its pgin function
  908.  * should fix things, but we might not be using that (e.g. if
  909.  * we're a subdatabase).
  910.  *
  911.  * Queue will create sparse files if sparse record numbers are used.
  912.  */
  913. if (pgno != 0 && PGNO(h) == 0) {
  914. for (p = (u_int8_t *)h; p < (u_int8_t *)h + dbp->pgsize; p++)
  915. if (*p != 0) {
  916. EPRINT((dbenv,
  917.     "Page %lu: partially zeroed page",
  918.     (u_long)pgno));
  919. ret = DB_VERIFY_BAD;
  920. goto err;
  921. }
  922. /*
  923.  * It's totally zeroed;  mark it as a hash, and we'll
  924.  * check that that makes sense structurally later.
  925.  * (The queue verification doesn't care, since queues
  926.  * don't really have much in the way of structure.)
  927.  */
  928. pip->type = P_HASH;
  929. F_SET(pip, VRFY_IS_ALLZEROES);
  930. ret = 0;
  931. goto err; /* well, not really an err. */
  932. }
  933. if (PGNO(h) != pgno) {
  934. EPRINT((dbenv, "Page %lu: bad page number %lu",
  935.     (u_long)pgno, (u_long)h->pgno));
  936. ret = DB_VERIFY_BAD;
  937. }
  938. if (!__db_is_valid_pagetype(h->type)) {
  939. EPRINT((dbenv, "Page %lu: bad page type %lu",
  940.     (u_long)pgno, (u_long)h->type));
  941. ret = DB_VERIFY_BAD;
  942. }
  943. pip->type = h->type;
  944. err: if ((t_ret = __db_vrfy_putpageinfo(dbenv, vdp, pip)) != 0 && ret == 0)
  945. ret = t_ret;
  946. return (ret);
  947. }
  948. /*
  949.  * __db_vrfy_invalid --
  950.  * Verify P_INVALID page.
  951.  * (Yes, there's not much to do here.)
  952.  */
  953. static int
  954. __db_vrfy_invalid(dbp, vdp, h, pgno, flags)
  955. DB *dbp;
  956. VRFY_DBINFO *vdp;
  957. PAGE *h;
  958. db_pgno_t pgno;
  959. u_int32_t flags;
  960. {
  961. DB_ENV *dbenv;
  962. VRFY_PAGEINFO *pip;
  963. int ret, t_ret;
  964. dbenv = dbp->dbenv;
  965. if ((ret = __db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0)
  966. return (ret);
  967. pip->next_pgno = pip->prev_pgno = 0;
  968. if (!IS_VALID_PGNO(NEXT_PGNO(h))) {
  969. EPRINT((dbenv, "Page %lu: invalid next_pgno %lu",
  970.     (u_long)pgno, (u_long)NEXT_PGNO(h)));
  971. ret = DB_VERIFY_BAD;
  972. } else
  973. pip->next_pgno = NEXT_PGNO(h);
  974. if ((t_ret = __db_vrfy_putpageinfo(dbenv, vdp, pip)) != 0 && ret == 0)
  975. ret = t_ret;
  976. return (ret);
  977. }
  978. /*
  979.  * __db_vrfy_datapage --
  980.  * Verify elements common to data pages (P_HASH, P_LBTREE,
  981.  * P_IBTREE, P_IRECNO, P_LRECNO, P_OVERFLOW, P_DUPLICATE)--i.e.,
  982.  * those defined in the PAGE structure.
  983.  *
  984.  * Called from each of the per-page routines, after the
  985.  * all-page-type-common elements of pip have been verified and filled
  986.  * in.
  987.  *
  988.  * PUBLIC: int __db_vrfy_datapage
  989.  * PUBLIC:     __P((DB *, VRFY_DBINFO *, PAGE *, db_pgno_t, u_int32_t));
  990.  */
  991. int
  992. __db_vrfy_datapage(dbp, vdp, h, pgno, flags)
  993. DB *dbp;
  994. VRFY_DBINFO *vdp;
  995. PAGE *h;
  996. db_pgno_t pgno;
  997. u_int32_t flags;
  998. {
  999. DB_ENV *dbenv;
  1000. VRFY_PAGEINFO *pip;
  1001. int isbad, ret, t_ret;
  1002. dbenv = dbp->dbenv;
  1003. if ((ret = __db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0)
  1004. return (ret);
  1005. isbad = 0;
  1006. /*
  1007.  * prev_pgno and next_pgno:  store for inter-page checks,
  1008.  * verify that they point to actual pages and not to self.
  1009.  *
  1010.  * !!!
  1011.  * Internal btree pages do not maintain these fields (indeed,
  1012.  * they overload them).  Skip.
  1013.  */
  1014. if (TYPE(h) != P_IBTREE && TYPE(h) != P_IRECNO) {
  1015. if (!IS_VALID_PGNO(PREV_PGNO(h)) || PREV_PGNO(h) == pip->pgno) {
  1016. isbad = 1;
  1017. EPRINT((dbenv, "Page %lu: invalid prev_pgno %lu",
  1018.     (u_long)pip->pgno, (u_long)PREV_PGNO(h)));
  1019. }
  1020. if (!IS_VALID_PGNO(NEXT_PGNO(h)) || NEXT_PGNO(h) == pip->pgno) {
  1021. isbad = 1;
  1022. EPRINT((dbenv, "Page %lu: invalid next_pgno %lu",
  1023.     (u_long)pip->pgno, (u_long)NEXT_PGNO(h)));
  1024. }
  1025. pip->prev_pgno = PREV_PGNO(h);
  1026. pip->next_pgno = NEXT_PGNO(h);
  1027. }
  1028. /*
  1029.  * Verify the number of entries on the page.
  1030.  * There is no good way to determine if this is accurate;  the
  1031.  * best we can do is verify that it's not more than can, in theory,
  1032.  * fit on the page.  Then, we make sure there are at least
  1033.  * this many valid elements in inp[], and hope that this catches
  1034.  * most cases.
  1035.  */
  1036. if (TYPE(h) != P_OVERFLOW) {
  1037. if (BKEYDATA_PSIZE(0) * NUM_ENT(h) > dbp->pgsize) {
  1038. isbad = 1;
  1039. EPRINT((dbenv, "Page %lu: too many entries: %lu",
  1040.     (u_long)pgno, (u_long)NUM_ENT(h)));
  1041. }
  1042. pip->entries = NUM_ENT(h);
  1043. }
  1044. /*
  1045.  * btree level.  Should be zero unless we're a btree;
  1046.  * if we are a btree, should be between LEAFLEVEL and MAXBTREELEVEL,
  1047.  * and we need to save it off.
  1048.  */
  1049. switch (TYPE(h)) {
  1050. case P_IBTREE:
  1051. case P_IRECNO:
  1052. if (LEVEL(h) < LEAFLEVEL + 1 || LEVEL(h) > MAXBTREELEVEL) {
  1053. isbad = 1;
  1054. EPRINT((dbenv, "Page %lu: bad btree level %lu",
  1055.     (u_long)pgno, (u_long)LEVEL(h)));
  1056. }
  1057. pip->bt_level = LEVEL(h);
  1058. break;
  1059. case P_LBTREE:
  1060. case P_LDUP:
  1061. case P_LRECNO:
  1062. if (LEVEL(h) != LEAFLEVEL) {
  1063. isbad = 1;
  1064. EPRINT((dbenv,
  1065.     "Page %lu: btree leaf page has incorrect level %lu",
  1066.     (u_long)pgno, (u_long)LEVEL(h)));
  1067. }
  1068. break;
  1069. default:
  1070. if (LEVEL(h) != 0) {
  1071. isbad = 1;
  1072. EPRINT((dbenv,
  1073.     "Page %lu: nonzero level %lu in non-btree database",
  1074.     (u_long)pgno, (u_long)LEVEL(h)));
  1075. }
  1076. break;
  1077. }
  1078. /*
  1079.  * Even though inp[] occurs in all PAGEs, we look at it in the
  1080.  * access-method-specific code, since btree and hash treat
  1081.  * item lengths very differently, and one of the most important
  1082.  * things we want to verify is that the data--as specified
  1083.  * by offset and length--cover the right part of the page
  1084.  * without overlaps, gaps, or violations of the page boundary.
  1085.  */
  1086. if ((t_ret = __db_vrfy_putpageinfo(dbenv, vdp, pip)) != 0 && ret == 0)
  1087. ret = t_ret;
  1088. return ((ret == 0 && isbad == 1) ? DB_VERIFY_BAD : ret);
  1089. }
  1090. /*
  1091.  * __db_vrfy_meta--
  1092.  * Verify the access-method common parts of a meta page, using
  1093.  * normal mpool routines.
  1094.  *
  1095.  * PUBLIC: int __db_vrfy_meta
  1096.  * PUBLIC:     __P((DB *, VRFY_DBINFO *, DBMETA *, db_pgno_t, u_int32_t));
  1097.  */
  1098. int
  1099. __db_vrfy_meta(dbp, vdp, meta, pgno, flags)
  1100. DB *dbp;
  1101. VRFY_DBINFO *vdp;
  1102. DBMETA *meta;
  1103. db_pgno_t pgno;
  1104. u_int32_t flags;
  1105. {
  1106. DB_ENV *dbenv;
  1107. DBTYPE dbtype, magtype;
  1108. VRFY_PAGEINFO *pip;
  1109. int isbad, ret, t_ret;
  1110. isbad = 0;
  1111. dbenv = dbp->dbenv;
  1112. if ((ret = __db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0)
  1113. return (ret);
  1114. /* type plausible for a meta page */
  1115. switch (meta->type) {
  1116. case P_BTREEMETA:
  1117. dbtype = DB_BTREE;
  1118. break;
  1119. case P_HASHMETA:
  1120. dbtype = DB_HASH;
  1121. break;
  1122. case P_QAMMETA:
  1123. dbtype = DB_QUEUE;
  1124. break;
  1125. default:
  1126. /* The verifier should never let us get here. */
  1127. DB_ASSERT(0);
  1128. ret = EINVAL;
  1129. goto err;
  1130. }
  1131. /* magic number valid */
  1132. if (!__db_is_valid_magicno(meta->magic, &magtype)) {
  1133. isbad = 1;
  1134. EPRINT((dbenv,
  1135.     "Page %lu: invalid magic number", (u_long)pgno));
  1136. }
  1137. if (magtype != dbtype) {
  1138. isbad = 1;
  1139. EPRINT((dbenv,
  1140.     "Page %lu: magic number does not match database type",
  1141.     (u_long)pgno));
  1142. }
  1143. /* version */
  1144. if ((dbtype == DB_BTREE &&
  1145.     (meta->version > DB_BTREEVERSION ||
  1146.     meta->version < DB_BTREEOLDVER)) ||
  1147.     (dbtype == DB_HASH &&
  1148.     (meta->version > DB_HASHVERSION ||
  1149.     meta->version < DB_HASHOLDVER)) ||
  1150.     (dbtype == DB_QUEUE &&
  1151.     (meta->version > DB_QAMVERSION ||
  1152.     meta->version < DB_QAMOLDVER))) {
  1153. isbad = 1;
  1154. EPRINT((dbenv,
  1155.     "Page %lu: unsupported database version %lu; extraneous errors may result",
  1156.     (u_long)pgno, (u_long)meta->version));
  1157. }
  1158. /* pagesize */
  1159. if (meta->pagesize != dbp->pgsize) {
  1160. isbad = 1;
  1161. EPRINT((dbenv, "Page %lu: invalid pagesize %lu",
  1162.     (u_long)pgno, (u_long)meta->pagesize));
  1163. }
  1164. /* free list */
  1165. /*
  1166.  * If this is not the main, master-database meta page, it
  1167.  * should not have a free list.
  1168.  */
  1169. if (pgno != PGNO_BASE_MD && meta->free != PGNO_INVALID) {
  1170. isbad = 1;
  1171. EPRINT((dbenv,
  1172.     "Page %lu: nonempty free list on subdatabase metadata page",
  1173.     (u_long)pgno));
  1174. }
  1175. /* Can correctly be PGNO_INVALID--that's just the end of the list. */
  1176. if (meta->free != PGNO_INVALID && IS_VALID_PGNO(meta->free))
  1177. pip->free = meta->free;
  1178. else if (!IS_VALID_PGNO(meta->free)) {
  1179. isbad = 1;
  1180. EPRINT((dbenv,
  1181.     "Page %lu: nonsensical free list pgno %lu",
  1182.     (u_long)pgno, (u_long)meta->free));
  1183. }
  1184. /*
  1185.  * We have now verified the common fields of the metadata page.
  1186.  * Clear the flag that told us they had been incompletely checked.
  1187.  */
  1188. F_CLR(pip, VRFY_INCOMPLETE);
  1189. err: if ((t_ret = __db_vrfy_putpageinfo(dbenv, vdp, pip)) != 0 && ret == 0)
  1190. ret = t_ret;
  1191. return ((ret == 0 && isbad == 1) ? DB_VERIFY_BAD : ret);
  1192. }
  1193. /*
  1194.  * __db_vrfy_freelist --
  1195.  * Walk free list, checking off pages and verifying absence of
  1196.  * loops.
  1197.  */
  1198. static int
  1199. __db_vrfy_freelist(dbp, vdp, meta, flags)
  1200. DB *dbp;
  1201. VRFY_DBINFO *vdp;
  1202. db_pgno_t meta;
  1203. u_int32_t flags;
  1204. {
  1205. DB *pgset;
  1206. DB_ENV *dbenv;
  1207. VRFY_PAGEINFO *pip;
  1208. db_pgno_t cur_pgno, next_pgno;
  1209. int p, ret, t_ret;
  1210. pgset = vdp->pgset;
  1211. DB_ASSERT(pgset != NULL);
  1212. dbenv = dbp->dbenv;
  1213. if ((ret = __db_vrfy_getpageinfo(vdp, meta, &pip)) != 0)
  1214. return (ret);
  1215. for (next_pgno = pip->free;
  1216.     next_pgno != PGNO_INVALID; next_pgno = pip->next_pgno) {
  1217. cur_pgno = pip->pgno;
  1218. if ((ret = __db_vrfy_putpageinfo(dbenv, vdp, pip)) != 0)
  1219. return (ret);
  1220. /* This shouldn't happen, but just in case. */
  1221. if (!IS_VALID_PGNO(next_pgno)) {
  1222. EPRINT((dbenv,
  1223.     "Page %lu: invalid next_pgno %lu on free list page",
  1224.     (u_long)cur_pgno, (u_long)next_pgno));
  1225. return (DB_VERIFY_BAD);
  1226. }
  1227. /* Detect cycles. */
  1228. if ((ret = __db_vrfy_pgset_get(pgset, next_pgno, &p)) != 0)
  1229. return (ret);
  1230. if (p != 0) {
  1231. EPRINT((dbenv,
  1232.     "Page %lu: page %lu encountered a second time on free list",
  1233.     (u_long)cur_pgno, (u_long)next_pgno));
  1234. return (DB_VERIFY_BAD);
  1235. }
  1236. if ((ret = __db_vrfy_pgset_inc(pgset, next_pgno)) != 0)
  1237. return (ret);
  1238. if ((ret = __db_vrfy_getpageinfo(vdp, next_pgno, &pip)) != 0)
  1239. return (ret);
  1240. if (pip->type != P_INVALID) {
  1241. EPRINT((dbenv,
  1242.     "Page %lu: non-invalid page %lu on free list",
  1243.     (u_long)cur_pgno, (u_long)next_pgno));
  1244. ret = DB_VERIFY_BAD;   /* unsafe to continue */
  1245. break;
  1246. }
  1247. }
  1248. if ((t_ret = __db_vrfy_putpageinfo(dbenv, vdp, pip)) != 0)
  1249. ret = t_ret;
  1250. return (ret);
  1251. }
  1252. /*
  1253.  * __db_vrfy_subdbs --
  1254.  * Walk the known-safe master database of subdbs with a cursor,
  1255.  * verifying the structure of each subdatabase we encounter.
  1256.  */
  1257. static int
  1258. __db_vrfy_subdbs(dbp, vdp, dbname, flags)
  1259. DB *dbp;
  1260. VRFY_DBINFO *vdp;
  1261. const char *dbname;
  1262. u_int32_t flags;
  1263. {
  1264. DB *mdbp;
  1265. DBC *dbc;
  1266. DBT key, data;
  1267. DB_ENV *dbenv;
  1268. VRFY_PAGEINFO *pip;
  1269. db_pgno_t meta_pgno;
  1270. int ret, t_ret, isbad;
  1271. u_int8_t type;
  1272. isbad = 0;
  1273. dbc = NULL;
  1274. dbenv = dbp->dbenv;
  1275. if ((ret =
  1276.     __db_master_open(dbp, NULL, dbname, DB_RDONLY, 0, &mdbp)) != 0)
  1277. return (ret);
  1278. if ((ret = __db_icursor(mdbp,
  1279.     NULL, DB_BTREE, PGNO_INVALID, 0, DB_LOCK_INVALIDID, &dbc)) != 0)
  1280. goto err;
  1281. memset(&key, 0, sizeof(key));
  1282. memset(&data, 0, sizeof(data));
  1283. while ((ret = dbc->c_get(dbc, &key, &data, DB_NEXT)) == 0) {
  1284. if (data.size != sizeof(db_pgno_t)) {
  1285. EPRINT((dbenv,
  1286.     "Subdatabase entry not page-number size"));
  1287. isbad = 1;
  1288. goto err;
  1289. }
  1290. memcpy(&meta_pgno, data.data, data.size);
  1291. /*
  1292.  * Subdatabase meta pgnos are stored in network byte
  1293.  * order for cross-endian compatibility.  Swap if appropriate.
  1294.  */
  1295. DB_NTOHL(&meta_pgno);
  1296. if (meta_pgno == PGNO_INVALID || meta_pgno > vdp->last_pgno) {
  1297. EPRINT((dbenv,
  1298.     "Subdatabase entry references invalid page %lu",
  1299.     (u_long)meta_pgno));
  1300. isbad = 1;
  1301. goto err;
  1302. }
  1303. if ((ret = __db_vrfy_getpageinfo(vdp, meta_pgno, &pip)) != 0)
  1304. goto err;
  1305. type = pip->type;
  1306. if ((ret = __db_vrfy_putpageinfo(dbenv, vdp, pip)) != 0)
  1307. goto err;
  1308. switch (type) {
  1309. case P_BTREEMETA:
  1310. if ((ret = __bam_vrfy_structure(
  1311.     dbp, vdp, meta_pgno, flags)) != 0) {
  1312. if (ret == DB_VERIFY_BAD)
  1313. isbad = 1;
  1314. else
  1315. goto err;
  1316. }
  1317. break;
  1318. case P_HASHMETA:
  1319. if ((ret = __ham_vrfy_structure(
  1320.     dbp, vdp, meta_pgno, flags)) != 0) {
  1321. if (ret == DB_VERIFY_BAD)
  1322. isbad = 1;
  1323. else
  1324. goto err;
  1325. }
  1326. break;
  1327. case P_QAMMETA:
  1328. default:
  1329. EPRINT((dbenv,
  1330.     "Subdatabase entry references page %lu of invalid type %lu",
  1331.     (u_long)meta_pgno, (u_long)type));
  1332. ret = DB_VERIFY_BAD;
  1333. goto err;
  1334. /* NOTREACHED */
  1335. }
  1336. }
  1337. if (ret == DB_NOTFOUND)
  1338. ret = 0;
  1339. err: if (dbc != NULL && (t_ret = __db_c_close(dbc)) != 0 && ret == 0)
  1340. ret = t_ret;
  1341. if ((t_ret = mdbp->close(mdbp, 0)) != 0 && ret == 0)
  1342. ret = t_ret;
  1343. return ((ret == 0 && isbad == 1) ? DB_VERIFY_BAD : ret);
  1344. }
  1345. /*
  1346.  * __db_vrfy_struct_feedback --
  1347.  * Provide feedback during top-down database structure traversal.
  1348.  * (See comment at the beginning of __db_vrfy_structure.)
  1349.  *
  1350.  * PUBLIC: void __db_vrfy_struct_feedback __P((DB *, VRFY_DBINFO *));
  1351.  */
  1352. void
  1353. __db_vrfy_struct_feedback(dbp, vdp)
  1354. DB *dbp;
  1355. VRFY_DBINFO *vdp;
  1356. {
  1357. int progress;
  1358. if (dbp->db_feedback == NULL)
  1359. return;
  1360. if (vdp->pgs_remaining > 0)
  1361. vdp->pgs_remaining--;
  1362. /* Don't allow a feedback call of 100 until we're really done. */
  1363. progress = 100 - (vdp->pgs_remaining * 50 / (vdp->last_pgno + 1));
  1364. dbp->db_feedback(dbp, DB_VERIFY, progress == 100 ? 99 : progress);
  1365. }
  1366. /*
  1367.  * __db_vrfy_orderchkonly --
  1368.  * Do an sort-order/hashing check on a known-otherwise-good subdb.
  1369.  */
  1370. static int
  1371. __db_vrfy_orderchkonly(dbp, vdp, name, subdb, flags)
  1372. DB *dbp;
  1373. VRFY_DBINFO *vdp;
  1374. const char *name, *subdb;
  1375. u_int32_t flags;
  1376. {
  1377. BTMETA *btmeta;
  1378. DB *mdbp, *pgset;
  1379. DBC *pgsc;
  1380. DBT key, data;
  1381. DB_ENV *dbenv;
  1382. DB_MPOOLFILE *mpf;
  1383. HASH *h_internal;
  1384. HMETA *hmeta;
  1385. PAGE *h, *currpg;
  1386. db_pgno_t meta_pgno, p, pgno;
  1387. u_int32_t bucket;
  1388. int t_ret, ret;
  1389. pgset = NULL;
  1390. pgsc = NULL;
  1391. dbenv = dbp->dbenv;
  1392. mpf = dbp->mpf;
  1393. currpg = h = NULL;
  1394. LF_CLR(DB_NOORDERCHK);
  1395. /* Open the master database and get the meta_pgno for the subdb. */
  1396. if ((ret = db_create(&mdbp, NULL, 0)) != 0)
  1397. return (ret);
  1398. if ((ret = __db_master_open(dbp, NULL, name, DB_RDONLY, 0, &mdbp)) != 0)
  1399. goto err;
  1400. memset(&key, 0, sizeof(key));
  1401. key.data = (void *)subdb;
  1402. key.size = (u_int32_t)strlen(subdb);
  1403. memset(&data, 0, sizeof(data));
  1404. if ((ret = mdbp->get(mdbp, NULL, &key, &data, 0)) != 0)
  1405. goto err;
  1406. if (data.size != sizeof(db_pgno_t)) {
  1407. EPRINT((dbenv, "Subdatabase entry of invalid size"));
  1408. ret = DB_VERIFY_BAD;
  1409. goto err;
  1410. }
  1411. memcpy(&meta_pgno, data.data, data.size);
  1412. /*
  1413.  * Subdatabase meta pgnos are stored in network byte
  1414.  * order for cross-endian compatibility.  Swap if appropriate.
  1415.  */
  1416. DB_NTOHL(&meta_pgno);
  1417. if ((ret = mpf->get(mpf, &meta_pgno, 0, &h)) != 0)
  1418. goto err;
  1419. if ((ret = __db_vrfy_pgset(dbenv, dbp->pgsize, &pgset)) != 0)
  1420. goto err;
  1421. switch (TYPE(h)) {
  1422. case P_BTREEMETA:
  1423. btmeta = (BTMETA *)h;
  1424. if (F_ISSET(&btmeta->dbmeta, BTM_RECNO)) {
  1425. /* Recnos have no order to check. */
  1426. ret = 0;
  1427. goto err;
  1428. }
  1429. if ((ret =
  1430.     __db_meta2pgset(dbp, vdp, meta_pgno, flags, pgset)) != 0)
  1431. goto err;
  1432. if ((ret = pgset->cursor(pgset, NULL, &pgsc, 0)) != 0)
  1433. goto err;
  1434. while ((ret = __db_vrfy_pgset_next(pgsc, &p)) == 0) {
  1435. if ((ret = mpf->get(mpf, &p, 0, &currpg)) != 0)
  1436. goto err;
  1437. if ((ret = __bam_vrfy_itemorder(dbp,
  1438.     NULL, currpg, p, NUM_ENT(currpg), 1,
  1439.     F_ISSET(&btmeta->dbmeta, BTM_DUP), flags)) != 0)
  1440. goto err;
  1441. if ((ret = mpf->put(mpf, currpg, 0)) != 0)
  1442. goto err;
  1443. currpg = NULL;
  1444. }
  1445. /*
  1446.  * The normal exit condition for the loop above is DB_NOTFOUND.
  1447.  * If we see that, zero it and continue on to cleanup.
  1448.  * Otherwise, it's a real error and will be returned.
  1449.  */
  1450. if (ret == DB_NOTFOUND)
  1451. ret = 0;
  1452. break;
  1453. case P_HASHMETA:
  1454. hmeta = (HMETA *)h;
  1455. h_internal = (HASH *)dbp->h_internal;
  1456. /*
  1457.  * Make sure h_charkey is right.
  1458.  */
  1459. if (h_internal == NULL) {
  1460. EPRINT((dbenv,
  1461.     "Page %lu: DB->h_internal field is NULL",
  1462.     (u_long)meta_pgno));
  1463. ret = DB_VERIFY_BAD;
  1464. goto err;
  1465. }
  1466. if (h_internal->h_hash == NULL)
  1467. h_internal->h_hash = hmeta->dbmeta.version < 5
  1468. ? __ham_func4 : __ham_func5;
  1469. if (hmeta->h_charkey !=
  1470.     h_internal->h_hash(dbp, CHARKEY, sizeof(CHARKEY))) {
  1471. EPRINT((dbenv,
  1472.     "Page %lu: incorrect hash function for database",
  1473.     (u_long)meta_pgno));
  1474. ret = DB_VERIFY_BAD;
  1475. goto err;
  1476. }
  1477. /*
  1478.  * Foreach bucket, verify hashing on each page in the
  1479.  * corresponding chain of pages.
  1480.  */
  1481. for (bucket = 0; bucket <= hmeta->max_bucket; bucket++) {
  1482. pgno = BS_TO_PAGE(bucket, hmeta->spares);
  1483. while (pgno != PGNO_INVALID) {
  1484. if ((ret = mpf->get(mpf,
  1485.     &pgno, 0, &currpg)) != 0)
  1486. goto err;
  1487. if ((ret = __ham_vrfy_hashing(dbp,
  1488.     NUM_ENT(currpg), hmeta, bucket, pgno,
  1489.     flags, h_internal->h_hash)) != 0)
  1490. goto err;
  1491. pgno = NEXT_PGNO(currpg);
  1492. if ((ret = mpf->put(mpf, currpg, 0)) != 0)
  1493. goto err;
  1494. currpg = NULL;
  1495. }
  1496. }
  1497. break;
  1498. default:
  1499. EPRINT((dbenv, "Page %lu: database metapage of bad type %lu",
  1500.     (u_long)meta_pgno, (u_long)TYPE(h)));
  1501. ret = DB_VERIFY_BAD;
  1502. break;
  1503. }
  1504. err: if (pgsc != NULL && (t_ret = pgsc->c_close(pgsc)) != 0 && ret == 0)
  1505. ret = t_ret;
  1506. if (pgset != NULL &&
  1507.     (t_ret = pgset->close(pgset, 0)) != 0 && ret == 0)
  1508. ret = t_ret;
  1509. if (h != NULL && (t_ret = mpf->put(mpf, h, 0)) != 0)
  1510. ret = t_ret;
  1511. if (currpg != NULL && (t_ret = mpf->put(mpf, currpg, 0)) != 0)
  1512. ret = t_ret;
  1513. if ((t_ret = mdbp->close(mdbp, 0)) != 0)
  1514. ret = t_ret;
  1515. return (ret);
  1516. }
  1517. /*
  1518.  * __db_salvage --
  1519.  * Walk through a page, salvaging all likely or plausible (w/
  1520.  * DB_AGGRESSIVE) key/data pairs.
  1521.  */
  1522. static int
  1523. __db_salvage(dbp, vdp, pgno, h, handle, callback, flags)
  1524. DB *dbp;
  1525. VRFY_DBINFO *vdp;
  1526. db_pgno_t pgno;
  1527. PAGE *h;
  1528. void *handle;
  1529. int (*callback) __P((void *, const void *));
  1530. u_int32_t flags;
  1531. {
  1532. DB_ASSERT(LF_ISSET(DB_SALVAGE));
  1533. /* If we got this page in the subdb pass, we can safely skip it. */
  1534. if (__db_salvage_isdone(vdp, pgno))
  1535. return (0);
  1536. switch (TYPE(h)) {
  1537. case P_HASH:
  1538. return (__ham_salvage(dbp,
  1539.     vdp, pgno, h, handle, callback, flags));
  1540. /* NOTREACHED */
  1541. case P_LBTREE:
  1542. return (__bam_salvage(dbp,
  1543.     vdp, pgno, P_LBTREE, h, handle, callback, NULL, flags));
  1544. /* NOTREACHED */
  1545. case P_LDUP:
  1546. return (__db_salvage_markneeded(vdp, pgno, SALVAGE_LDUP));
  1547. /* NOTREACHED */
  1548. case P_OVERFLOW:
  1549. return (__db_salvage_markneeded(vdp, pgno, SALVAGE_OVERFLOW));
  1550. /* NOTREACHED */
  1551. case P_LRECNO:
  1552. /*
  1553.  * Recnos are tricky -- they may represent dup pages, or
  1554.  * they may be subdatabase/regular database pages in their
  1555.  * own right.  If the former, they need to be printed with a
  1556.  * key, preferably when we hit the corresponding datum in
  1557.  * a btree/hash page.  If the latter, there is no key.
  1558.  *
  1559.  * If a database is sufficiently frotzed, we're not going
  1560.  * to be able to get this right, so we best-guess:  just
  1561.  * mark it needed now, and if we're really a normal recno
  1562.  * database page, the "unknowns" pass will pick us up.
  1563.  */
  1564. return (__db_salvage_markneeded(vdp, pgno, SALVAGE_LRECNO));
  1565. /* NOTREACHED */
  1566. case P_IBTREE:
  1567. case P_INVALID:
  1568. case P_IRECNO:
  1569. case __P_DUPLICATE:
  1570. default:
  1571. /* XXX: Should we be more aggressive here? */
  1572. break;
  1573. }
  1574. return (0);
  1575. }
  1576. /*
  1577.  * __db_salvage_unknowns --
  1578.  * Walk through the salvager database, printing with key "UNKNOWN"
  1579.  * any pages we haven't dealt with.
  1580.  */
  1581. static int
  1582. __db_salvage_unknowns(dbp, vdp, handle, callback, flags)
  1583. DB *dbp;
  1584. VRFY_DBINFO *vdp;
  1585. void *handle;
  1586. int (*callback) __P((void *, const void *));
  1587. u_int32_t flags;
  1588. {
  1589. DBT unkdbt, key, *dbt;
  1590. DB_ENV *dbenv;
  1591. DB_MPOOLFILE *mpf;
  1592. PAGE *h;
  1593. db_pgno_t pgno;
  1594. u_int32_t pgtype;
  1595. int ret, err_ret;
  1596. void *ovflbuf;
  1597. dbenv = dbp->dbenv;
  1598. mpf = dbp->mpf;
  1599. memset(&unkdbt, 0, sizeof(DBT));
  1600. unkdbt.size = (u_int32_t)strlen("UNKNOWN") + 1;
  1601. unkdbt.data = "UNKNOWN";
  1602. if ((ret = __os_malloc(dbenv, dbp->pgsize, &ovflbuf)) != 0)
  1603. return (ret);
  1604. err_ret = 0;
  1605. while ((ret = __db_salvage_getnext(vdp, &pgno, &pgtype)) == 0) {
  1606. dbt = NULL;
  1607. if ((ret = mpf->get(mpf, &pgno, 0, &h)) != 0) {
  1608. err_ret = ret;
  1609. continue;
  1610. }
  1611. switch (pgtype) {
  1612. case SALVAGE_LDUP:
  1613. case SALVAGE_LRECNODUP:
  1614. dbt = &unkdbt;
  1615. /* FALLTHROUGH */
  1616. case SALVAGE_LBTREE:
  1617. case SALVAGE_LRECNO:
  1618. if ((ret = __bam_salvage(dbp, vdp, pgno, pgtype,
  1619.     h, handle, callback, dbt, flags)) != 0)
  1620. err_ret = ret;
  1621. break;
  1622. case SALVAGE_OVERFLOW:
  1623. /*
  1624.  * XXX:
  1625.  * This may generate multiple "UNKNOWN" keys in
  1626.  * a database with no dups.  What to do?
  1627.  */
  1628. if ((ret = __db_safe_goff(dbp,
  1629.     vdp, pgno, &key, &ovflbuf, flags)) != 0 ||
  1630.     (ret = __db_prdbt(&key,
  1631.     0, " ", handle, callback, 0, vdp)) != 0 ||
  1632.     (ret = __db_prdbt(&unkdbt,
  1633.     0, " ", handle, callback, 0, vdp)) != 0)
  1634. err_ret = ret;
  1635. break;
  1636. case SALVAGE_HASH:
  1637. if ((ret = __ham_salvage(
  1638.     dbp, vdp, pgno, h, handle, callback, flags)) != 0)
  1639. err_ret = ret;
  1640. break;
  1641. case SALVAGE_INVALID:
  1642. case SALVAGE_IGNORE:
  1643. default:
  1644. /*
  1645.  * Shouldn't happen, but if it does, just do what the
  1646.  * nice man says.
  1647.  */
  1648. DB_ASSERT(0);
  1649. break;
  1650. }
  1651. if ((ret = mpf->put(mpf, h, 0)) != 0)
  1652. err_ret = ret;
  1653. }
  1654. __os_free(dbenv, ovflbuf);
  1655. if (err_ret != 0 && ret == 0)
  1656. ret = err_ret;
  1657. return (ret == DB_NOTFOUND ? 0 : ret);
  1658. }
  1659. /*
  1660.  * Offset of the ith inp array entry, which we can compare to the offset
  1661.  * the entry stores.
  1662.  */
  1663. #define INP_OFFSET(dbp, h, i)
  1664.     ((db_indx_t)((u_int8_t *)((P_INP(dbp,(h))) + (i)) - (u_int8_t *)(h)))
  1665. /*
  1666.  * __db_vrfy_inpitem --
  1667.  * Verify that a single entry in the inp array is sane, and update
  1668.  * the high water mark and current item offset.  (The former of these is
  1669.  * used for state information between calls, and is required;  it must
  1670.  * be initialized to the pagesize before the first call.)
  1671.  *
  1672.  * Returns DB_VERIFY_FATAL if inp has collided with the data,
  1673.  * since verification can't continue from there;  returns DB_VERIFY_BAD
  1674.  * if anything else is wrong.
  1675.  *
  1676.  * PUBLIC: int __db_vrfy_inpitem __P((DB *, PAGE *,
  1677.  * PUBLIC:     db_pgno_t, u_int32_t, int, u_int32_t, u_int32_t *, u_int32_t *));
  1678.  */
  1679. int
  1680. __db_vrfy_inpitem(dbp, h, pgno, i, is_btree, flags, himarkp, offsetp)
  1681. DB *dbp;
  1682. PAGE *h;
  1683. db_pgno_t pgno;
  1684. u_int32_t i;
  1685. int is_btree;
  1686. u_int32_t flags, *himarkp, *offsetp;
  1687. {
  1688. BKEYDATA *bk;
  1689. DB_ENV *dbenv;
  1690. db_indx_t *inp, offset, len;
  1691. dbenv = dbp->dbenv;
  1692. DB_ASSERT(himarkp != NULL);
  1693. inp = P_INP(dbp, h);
  1694. /*
  1695.  * Check that the inp array, which grows from the beginning of the
  1696.  * page forward, has not collided with the data, which grow from the
  1697.  * end of the page backward.
  1698.  */
  1699. if (inp + i >= (db_indx_t *)((u_int8_t *)h + *himarkp)) {
  1700. /* We've collided with the data.  We need to bail. */
  1701. EPRINT((dbenv, "Page %lu: entries listing %lu overlaps data",
  1702.     (u_long)pgno, (u_long)i));
  1703. return (DB_VERIFY_FATAL);
  1704. }
  1705. offset = inp[i];
  1706. /*
  1707.  * Check that the item offset is reasonable:  it points somewhere
  1708.  * after the inp array and before the end of the page.
  1709.  */
  1710. if (offset <= INP_OFFSET(dbp, h, i) || offset > dbp->pgsize) {
  1711. EPRINT((dbenv, "Page %lu: bad offset %lu at page index %lu",
  1712.     (u_long)pgno, (u_long)offset, (u_long)i));
  1713. return (DB_VERIFY_BAD);
  1714. }
  1715. /* Update the high-water mark (what HOFFSET should be) */
  1716. if (offset < *himarkp)
  1717. *himarkp = offset;
  1718. if (is_btree) {
  1719. /*
  1720.  * Check that the item length remains on-page.
  1721.  */
  1722. bk = GET_BKEYDATA(dbp, h, i);
  1723. /*
  1724.  * We need to verify the type of the item here;
  1725.  * we can't simply assume that it will be one of the
  1726.  * expected three.  If it's not a recognizable type,
  1727.  * it can't be considered to have a verifiable
  1728.  * length, so it's not possible to certify it as safe.
  1729.  */
  1730. switch (B_TYPE(bk->type)) {
  1731. case B_KEYDATA:
  1732. len = bk->len;
  1733. break;
  1734. case B_DUPLICATE:
  1735. case B_OVERFLOW:
  1736. len = BOVERFLOW_SIZE;
  1737. break;
  1738. default:
  1739. EPRINT((dbenv,
  1740.     "Page %lu: item %lu of unrecognizable type",
  1741.     (u_long)pgno, (u_long)i));
  1742. return (DB_VERIFY_BAD);
  1743. }
  1744. if ((size_t)(offset + len) > dbp->pgsize) {
  1745. EPRINT((dbenv,
  1746.     "Page %lu: item %lu extends past page boundary",
  1747.     (u_long)pgno, (u_long)i));
  1748. return (DB_VERIFY_BAD);
  1749. }
  1750. }
  1751. if (offsetp != NULL)
  1752. *offsetp = offset;
  1753. return (0);
  1754. }
  1755. /*
  1756.  * __db_vrfy_duptype--
  1757.  * Given a page number and a set of flags to __bam_vrfy_subtree,
  1758.  * verify that the dup tree type is correct--i.e., it's a recno
  1759.  * if DUPSORT is not set and a btree if it is.
  1760.  *
  1761.  * PUBLIC: int __db_vrfy_duptype
  1762.  * PUBLIC:     __P((DB *, VRFY_DBINFO *, db_pgno_t, u_int32_t));
  1763.  */
  1764. int
  1765. __db_vrfy_duptype(dbp, vdp, pgno, flags)
  1766. DB *dbp;
  1767. VRFY_DBINFO *vdp;
  1768. db_pgno_t pgno;
  1769. u_int32_t flags;
  1770. {
  1771. DB_ENV *dbenv;
  1772. VRFY_PAGEINFO *pip;
  1773. int ret, isbad;
  1774. dbenv = dbp->dbenv;
  1775. isbad = 0;
  1776. if ((ret = __db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0)
  1777. return (ret);
  1778. switch (pip->type) {
  1779. case P_IBTREE:
  1780. case P_LDUP:
  1781. if (!LF_ISSET(ST_DUPSORT)) {
  1782. EPRINT((dbenv,
  1783.     "Page %lu: sorted duplicate set in unsorted-dup database",
  1784.     (u_long)pgno));
  1785. isbad = 1;
  1786. }
  1787. break;
  1788. case P_IRECNO:
  1789. case P_LRECNO:
  1790. if (LF_ISSET(ST_DUPSORT)) {
  1791. EPRINT((dbenv,
  1792.     "Page %lu: unsorted duplicate set in sorted-dup database",
  1793.     (u_long)pgno));
  1794. isbad = 1;
  1795. }
  1796. break;
  1797. default:
  1798. /*
  1799.  * If the page is entirely zeroed, its pip->type will be a lie
  1800.  * (we assumed it was a hash page, as they're allowed to be
  1801.  * zeroed);  handle this case specially.
  1802.  */
  1803. if (F_ISSET(pip, VRFY_IS_ALLZEROES))
  1804. ZEROPG_ERR_PRINT(dbenv, pgno, "duplicate page");
  1805. else
  1806. EPRINT((dbenv,
  1807.     "Page %lu: duplicate page of inappropriate type %lu",
  1808.     (u_long)pgno, (u_long)pip->type));
  1809. isbad = 1;
  1810. break;
  1811. }
  1812. if ((ret = __db_vrfy_putpageinfo(dbenv, vdp, pip)) != 0)
  1813. return (ret);
  1814. return (isbad == 1 ? DB_VERIFY_BAD : 0);
  1815. }
  1816. /*
  1817.  * __db_salvage_duptree --
  1818.  * Attempt to salvage a given duplicate tree, given its alleged root.
  1819.  *
  1820.  * The key that corresponds to this dup set has been passed to us
  1821.  * in DBT *key.  Because data items follow keys, though, it has been
  1822.  * printed once already.
  1823.  *
  1824.  * The basic idea here is that pgno ought to be a P_LDUP, a P_LRECNO, a
  1825.  * P_IBTREE, or a P_IRECNO.  If it's an internal page, use the verifier
  1826.  * functions to make sure it's safe;  if it's not, we simply bail and the
  1827.  * data will have to be printed with no key later on.  if it is safe,
  1828.  * recurse on each of its children.
  1829.  *
  1830.  * Whether or not it's safe, if it's a leaf page, __bam_salvage it.
  1831.  *
  1832.  * At all times, use the DB hanging off vdp to mark and check what we've
  1833.  * done, so each page gets printed exactly once and we don't get caught
  1834.  * in any cycles.
  1835.  *
  1836.  * PUBLIC: int __db_salvage_duptree __P((DB *, VRFY_DBINFO *, db_pgno_t,
  1837.  * PUBLIC:     DBT *, void *, int (*)(void *, const void *), u_int32_t));
  1838.  */
  1839. int
  1840. __db_salvage_duptree(dbp, vdp, pgno, key, handle, callback, flags)
  1841. DB *dbp;
  1842. VRFY_DBINFO *vdp;
  1843. db_pgno_t pgno;
  1844. DBT *key;
  1845. void *handle;
  1846. int (*callback) __P((void *, const void *));
  1847. u_int32_t flags;
  1848. {
  1849. DB_MPOOLFILE *mpf;
  1850. PAGE *h;
  1851. int ret, t_ret;
  1852. mpf = dbp->mpf;
  1853. if (pgno == PGNO_INVALID || !IS_VALID_PGNO(pgno))
  1854. return (DB_VERIFY_BAD);
  1855. /* We have a plausible page.  Try it. */
  1856. if ((ret = mpf->get(mpf, &pgno, 0, &h)) != 0)
  1857. return (ret);
  1858. switch (TYPE(h)) {
  1859. case P_IBTREE:
  1860. case P_IRECNO:
  1861. if ((ret = __db_vrfy_common(dbp, vdp, h, pgno, flags)) != 0)
  1862. goto err;
  1863. if ((ret = __bam_vrfy(dbp,
  1864.     vdp, h, pgno, flags | DB_NOORDERCHK)) != 0 ||
  1865.     (ret = __db_salvage_markdone(vdp, pgno)) != 0)
  1866. goto err;
  1867. /*
  1868.  * We have a known-healthy internal page.  Walk it.
  1869.  */
  1870. if ((ret = __bam_salvage_walkdupint(dbp, vdp, h, key,
  1871.     handle, callback, flags)) != 0)
  1872. goto err;
  1873. break;
  1874. case P_LRECNO:
  1875. case P_LDUP:
  1876. if ((ret = __bam_salvage(dbp,
  1877.     vdp, pgno, TYPE(h), h, handle, callback, key, flags)) != 0)
  1878. goto err;
  1879. break;
  1880. default:
  1881. ret = DB_VERIFY_BAD;
  1882. goto err;
  1883. /* NOTREACHED */
  1884. }
  1885. err: if ((t_ret = mpf->put(mpf, h, 0)) != 0 && ret == 0)
  1886. ret = t_ret;
  1887. return (ret);
  1888. }
  1889. /*
  1890.  * __db_salvage_subdbs --
  1891.  * Check and see if this database has subdbs;  if so, try to salvage
  1892.  * them independently.
  1893.  */
  1894. static int
  1895. __db_salvage_subdbs(dbp, vdp, handle, callback, flags, hassubsp)
  1896. DB *dbp;
  1897. VRFY_DBINFO *vdp;
  1898. void *handle;
  1899. int (*callback) __P((void *, const void *));
  1900. u_int32_t flags;
  1901. int *hassubsp;
  1902. {
  1903. BTMETA *btmeta;
  1904. DB *pgset;
  1905. DBC *pgsc;
  1906. DB_MPOOLFILE *mpf;
  1907. PAGE *h;
  1908. db_pgno_t p, meta_pgno;
  1909. int ret, err_ret;
  1910. pgset = NULL;
  1911. pgsc = NULL;
  1912. mpf = dbp->mpf;
  1913. err_ret = 0;
  1914. meta_pgno = PGNO_BASE_MD;
  1915. if ((ret = mpf->get(mpf, &meta_pgno, 0, &h)) != 0)
  1916. return (ret);
  1917. if (TYPE(h) == P_BTREEMETA)
  1918. btmeta = (BTMETA *)h;
  1919. else {
  1920. /* Not a btree metadata, ergo no subdbs, so just return. */
  1921. ret = 0;
  1922. goto err;
  1923. }
  1924. /* If it's not a safe page, bail on the attempt. */
  1925. if ((ret = __db_vrfy_common(dbp, vdp, h, PGNO_BASE_MD, flags)) != 0 ||
  1926.    (ret = __bam_vrfy_meta(dbp, vdp, btmeta, PGNO_BASE_MD, flags)) != 0)
  1927. goto err;
  1928. if (!F_ISSET(&btmeta->dbmeta, BTM_SUBDB)) {
  1929. /* No subdbs, just return. */
  1930. ret = 0;
  1931. goto err;
  1932. }
  1933. /* We think we've got subdbs.  Mark it so. */
  1934. *hassubsp = 1;
  1935. if ((ret = mpf->put(mpf, h, 0)) != 0)
  1936. return (ret);
  1937. /*
  1938.  * We have subdbs.  Try to crack them.
  1939.  *
  1940.  * To do so, get a set of leaf pages in the master
  1941.  * database, and then walk each of the valid ones, salvaging
  1942.  * subdbs as we go.  If any prove invalid, just drop them;  we'll
  1943.  * pick them up on a later pass.
  1944.  */
  1945. if ((ret = __db_vrfy_pgset(dbp->dbenv, dbp->pgsize, &pgset)) != 0)
  1946. return (ret);
  1947. if ((ret =
  1948.     __db_meta2pgset(dbp, vdp, PGNO_BASE_MD, flags, pgset)) != 0)
  1949. goto err;
  1950. if ((ret = pgset->cursor(pgset, NULL, &pgsc, 0)) != 0)
  1951. goto err;
  1952. while ((ret = __db_vrfy_pgset_next(pgsc, &p)) == 0) {
  1953. if ((ret = mpf->get(mpf, &p, 0, &h)) != 0) {
  1954. err_ret = ret;
  1955. continue;
  1956. }
  1957. if ((ret = __db_vrfy_common(dbp, vdp, h, p, flags)) != 0 ||
  1958.     (ret = __bam_vrfy(dbp,
  1959.     vdp, h, p, flags | DB_NOORDERCHK)) != 0)
  1960. goto nextpg;
  1961. if (TYPE(h) != P_LBTREE)
  1962. goto nextpg;
  1963. else if ((ret = __db_salvage_subdbpg(
  1964.     dbp, vdp, h, handle, callback, flags)) != 0)
  1965. err_ret = ret;
  1966. nextpg: if ((ret = mpf->put(mpf, h, 0)) != 0)
  1967. err_ret = ret;
  1968. }
  1969. if (ret != DB_NOTFOUND)
  1970. goto err;
  1971. if ((ret = pgsc->c_close(pgsc)) != 0)
  1972. goto err;
  1973. ret = pgset->close(pgset, 0);
  1974. return ((ret == 0 && err_ret != 0) ? err_ret : ret);
  1975. /* NOTREACHED */
  1976. err: if (pgsc != NULL)
  1977. (void)pgsc->c_close(pgsc);
  1978. if (pgset != NULL)
  1979. (void)pgset->close(pgset, 0);
  1980. (void)mpf->put(mpf, h, 0);
  1981. return (ret);
  1982. }
  1983. /*
  1984.  * __db_salvage_subdbpg --
  1985.  * Given a known-good leaf page in the master database, salvage all
  1986.  * leaf pages corresponding to each subdb.
  1987.  */
  1988. static int
  1989. __db_salvage_subdbpg(dbp, vdp, master, handle, callback, flags)
  1990. DB *dbp;
  1991. VRFY_DBINFO *vdp;
  1992. PAGE *master;
  1993. void *handle;
  1994. int (*callback) __P((void *, const void *));
  1995. u_int32_t flags;
  1996. {
  1997. BKEYDATA *bkkey, *bkdata;
  1998. BOVERFLOW *bo;
  1999. DB *pgset;
  2000. DBC *pgsc;
  2001. DBT key;
  2002. DB_ENV *dbenv;
  2003. DB_MPOOLFILE *mpf;
  2004. PAGE *subpg;
  2005. db_indx_t i;
  2006. db_pgno_t meta_pgno, p;
  2007. int ret, err_ret, t_ret;
  2008. char *subdbname;
  2009. dbenv = dbp->dbenv;
  2010. mpf = dbp->mpf;
  2011. ret = err_ret = 0;
  2012. subdbname = NULL;
  2013. if ((ret = __db_vrfy_pgset(dbenv, dbp->pgsize, &pgset)) != 0)
  2014. return (ret);
  2015. /*
  2016.  * For each entry, get and salvage the set of pages
  2017.  * corresponding to that entry.
  2018.  */
  2019. for (i = 0; i < NUM_ENT(master); i += P_INDX) {
  2020. bkkey = GET_BKEYDATA(dbp, master, i);
  2021. bkdata = GET_BKEYDATA(dbp, master, i + O_INDX);
  2022. /* Get the subdatabase name. */
  2023. if (B_TYPE(bkkey->type) == B_OVERFLOW) {
  2024. /*
  2025.  * We can, in principle anyway, have a subdb
  2026.  * name so long it overflows.  Ick.
  2027.  */
  2028. bo = (BOVERFLOW *)bkkey;
  2029. if ((ret = __db_safe_goff(dbp, vdp, bo->pgno, &key,
  2030.     (void **)&subdbname, flags)) != 0) {
  2031. err_ret = DB_VERIFY_BAD;
  2032. continue;
  2033. }
  2034. /* Nul-terminate it. */
  2035. if ((ret = __os_realloc(dbenv,
  2036.     key.size + 1, &subdbname)) != 0)
  2037. goto err;
  2038. subdbname[key.size] = '';
  2039. } else if (B_TYPE(bkkey->type == B_KEYDATA)) {
  2040. if ((ret = __os_realloc(dbenv,
  2041.     bkkey->len + 1, &subdbname)) != 0)
  2042. goto err;
  2043. memcpy(subdbname, bkkey->data, bkkey->len);
  2044. subdbname[bkkey->len] = '';
  2045. }
  2046. /* Get the corresponding pgno. */
  2047. if (bkdata->len != sizeof(db_pgno_t)) {
  2048. err_ret = DB_VERIFY_BAD;
  2049. continue;
  2050. }
  2051. memcpy(&meta_pgno, bkdata->data, sizeof(db_pgno_t));
  2052. /*
  2053.  * Subdatabase meta pgnos are stored in network byte
  2054.  * order for cross-endian compatibility.  Swap if appropriate.
  2055.  */
  2056. DB_NTOHL(&meta_pgno);
  2057. /* If we can't get the subdb meta page, just skip the subdb. */
  2058. if (!IS_VALID_PGNO(meta_pgno) ||
  2059.     (ret = mpf->get(mpf, &meta_pgno, 0, &subpg)) != 0) {
  2060. err_ret = ret;
  2061. continue;
  2062. }
  2063. /*
  2064.  * Verify the subdatabase meta page.  This has two functions.
  2065.  * First, if it's bad, we have no choice but to skip the subdb
  2066.  * and let the pages just get printed on a later pass.  Second,
  2067.  * the access-method-specific meta verification routines record
  2068.  * the various state info (such as the presence of dups)
  2069.  * that we need for __db_prheader().
  2070.  */
  2071. if ((ret =
  2072.     __db_vrfy_common(dbp, vdp, subpg, meta_pgno, flags)) != 0) {
  2073. err_ret = ret;
  2074. (void)mpf->put(mpf, subpg, 0);
  2075. continue;
  2076. }
  2077. switch (TYPE(subpg)) {
  2078. case P_BTREEMETA:
  2079. if ((ret = __bam_vrfy_meta(dbp,
  2080.     vdp, (BTMETA *)subpg, meta_pgno, flags)) != 0) {
  2081. err_ret = ret;
  2082. (void)mpf->put(mpf, subpg, 0);
  2083. continue;
  2084. }
  2085. break;
  2086. case P_HASHMETA:
  2087. if ((ret = __ham_vrfy_meta(dbp,
  2088.     vdp, (HMETA *)subpg, meta_pgno, flags)) != 0) {
  2089. err_ret = ret;
  2090. (void)mpf->put(mpf, subpg, 0);
  2091. continue;
  2092. }
  2093. break;
  2094. default:
  2095. /* This isn't an appropriate page;  skip this subdb. */
  2096. err_ret = DB_VERIFY_BAD;
  2097. continue;
  2098. /* NOTREACHED */
  2099. }
  2100. if ((ret = mpf->put(mpf, subpg, 0)) != 0) {
  2101. err_ret = ret;
  2102. continue;
  2103. }
  2104. /* Print a subdatabase header. */
  2105. if ((ret = __db_prheader(dbp,
  2106.     subdbname, 0, 0, handle, callback, vdp, meta_pgno)) != 0)
  2107. goto err;
  2108. if ((ret = __db_meta2pgset(dbp, vdp, meta_pgno,
  2109.     flags, pgset)) != 0) {
  2110. err_ret = ret;
  2111. continue;
  2112. }
  2113. if ((ret = pgset->cursor(pgset, NULL, &pgsc, 0)) != 0)
  2114. goto err;
  2115. while ((ret = __db_vrfy_pgset_next(pgsc, &p)) == 0) {
  2116. if ((ret = mpf->get(mpf, &p, 0, &subpg)) != 0) {
  2117. err_ret = ret;
  2118. continue;
  2119. }
  2120. if ((ret = __db_salvage(dbp, vdp, p, subpg,
  2121.     handle, callback, flags)) != 0)
  2122. err_ret = ret;
  2123. if ((ret = mpf->put(mpf, subpg, 0)) != 0)
  2124. err_ret = ret;
  2125. }
  2126. if (ret != DB_NOTFOUND)
  2127. goto err;
  2128. if ((ret = pgsc->c_close(pgsc)) != 0)
  2129. goto err;
  2130. if ((ret = __db_prfooter(handle, callback)) != 0)
  2131. goto err;
  2132. }
  2133. err: if (subdbname)
  2134. __os_free(dbenv, subdbname);
  2135. if ((t_ret = pgset->close(pgset, 0)) != 0)
  2136. ret = t_ret;
  2137. if ((t_ret = __db_salvage_markdone(vdp, PGNO(master))) != 0)
  2138. return (t_ret);
  2139. return ((err_ret != 0) ? err_ret : ret);
  2140. }
  2141. /*
  2142.  * __db_meta2pgset --
  2143.  * Given a known-safe meta page number, return the set of pages
  2144.  * corresponding to the database it represents.  Return DB_VERIFY_BAD if
  2145.  * it's not a suitable meta page or is invalid.
  2146.  */
  2147. static int
  2148. __db_meta2pgset(dbp, vdp, pgno, flags, pgset)
  2149. DB *dbp;
  2150. VRFY_DBINFO *vdp;
  2151. db_pgno_t pgno;
  2152. u_int32_t flags;
  2153. DB *pgset;
  2154. {
  2155. DB_MPOOLFILE *mpf;
  2156. PAGE *h;
  2157. int ret, t_ret;
  2158. mpf = dbp->mpf;
  2159. if ((ret = mpf->get(mpf, &pgno, 0, &h)) != 0)
  2160. return (ret);
  2161. switch (TYPE(h)) {
  2162. case P_BTREEMETA:
  2163. ret = __bam_meta2pgset(dbp, vdp, (BTMETA *)h, flags, pgset);
  2164. break;
  2165. case P_HASHMETA:
  2166. ret = __ham_meta2pgset(dbp, vdp, (HMETA *)h, flags, pgset);
  2167. break;
  2168. default:
  2169. ret = DB_VERIFY_BAD;
  2170. break;
  2171. }
  2172. if ((t_ret = mpf->put(mpf, h, 0)) != 0)
  2173. return (t_ret);
  2174. return (ret);
  2175. }
  2176. /*
  2177.  * __db_guesspgsize --
  2178.  * Try to guess what the pagesize is if the one on the meta page
  2179.  * and the one in the db are invalid.
  2180.  */
  2181. static int
  2182. __db_guesspgsize(dbenv, fhp)
  2183. DB_ENV *dbenv;
  2184. DB_FH *fhp;
  2185. {
  2186. db_pgno_t i;
  2187. size_t nr;
  2188. u_int32_t guess;
  2189. u_int8_t type;
  2190. for (guess = DB_MAX_PGSIZE; guess >= DB_MIN_PGSIZE; guess >>= 1) {
  2191. /*
  2192.  * We try to read three pages ahead after the first one
  2193.  * and make sure we have plausible types for all of them.
  2194.  * If the seeks fail, continue with a smaller size;
  2195.  * we're probably just looking past the end of the database.
  2196.  * If they succeed and the types are reasonable, also continue
  2197.  * with a size smaller;  we may be looking at pages N,
  2198.  * 2N, and 3N for some N > 1.
  2199.  *
  2200.  * As soon as we hit an invalid type, we stop and return
  2201.  * our previous guess; that last one was probably the page size.
  2202.  */
  2203. for (i = 1; i <= 3; i++) {
  2204. if (__os_seek(dbenv, fhp, guess,
  2205.     i, SSZ(DBMETA, type), 0, DB_OS_SEEK_SET) != 0)
  2206. break;
  2207. if (__os_read(dbenv,
  2208.     fhp, &type, 1, &nr) != 0 || nr == 0)
  2209. break;
  2210. if (type == P_INVALID || type >= P_PAGETYPE_MAX)
  2211. return (guess << 1);
  2212. }
  2213. }
  2214. /*
  2215.  * If we're just totally confused--the corruption takes up most of the
  2216.  * beginning pages of the database--go with the default size.
  2217.  */
  2218. return (DB_DEF_IOSIZE);
  2219. }