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

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. #include "db_config.h"
  8. #ifndef lint
  9. static const char revid[] = "$Id: db_server_cxxutil.cpp,v 1.8 2002/05/23 07:49:34 mjc Exp $";
  10. #endif /* not lint */
  11. #ifndef NO_SYSTEM_INCLUDES
  12. #include <sys/types.h>
  13. #if TIME_WITH_SYS_TIME
  14. #include <sys/time.h>
  15. #include <time.h>
  16. #else
  17. #if HAVE_SYS_TIME_H
  18. #include <sys/time.h>
  19. #else
  20. #include <time.h>
  21. #endif
  22. #endif
  23. #include <rpc/rpc.h>
  24. #include <limits.h>
  25. #include <signal.h>
  26. #include <stdio.h>
  27. #include <stdlib.h>
  28. #include <string.h>
  29. #include <unistd.h>
  30. #endif
  31. #include "dbinc_auto/db_server.h"
  32. #include "db_int.h"
  33. #include "db_cxx.h"
  34. #include "dbinc_auto/clib_ext.h"
  35. extern "C" {
  36. #include "dbinc/db_server_int.h"
  37. #include "dbinc_auto/rpc_server_ext.h"
  38. #include "dbinc_auto/common_ext.h"
  39. extern int __dbsrv_main  __P((void));
  40. }
  41. static int add_home __P((char *));
  42. static int add_passwd __P((char *));
  43. static int env_recover __P((char *));
  44. static void __dbclear_child __P((ct_entry *));
  45. static LIST_HEAD(cthead, ct_entry) __dbsrv_head;
  46. static LIST_HEAD(homehead, home_entry) __dbsrv_home;
  47. static long __dbsrv_defto = DB_SERVER_TIMEOUT;
  48. static long __dbsrv_maxto = DB_SERVER_MAXTIMEOUT;
  49. static long __dbsrv_idleto = DB_SERVER_IDLETIMEOUT;
  50. static char *logfile = NULL;
  51. static char *prog;
  52. static void usage __P((char *));
  53. static void version_check __P((void));
  54. int __dbsrv_verbose = 0;
  55. int
  56. main(
  57. int argc,
  58. char **argv)
  59. {
  60. extern char *optarg;
  61. CLIENT *cl;
  62. int ch, ret;
  63. char *passwd;
  64. prog = argv[0];
  65. version_check();
  66. /*
  67.  * Check whether another server is running or not.  There
  68.  * is a race condition where two servers could be racing to
  69.  * register with the portmapper.  The goal of this check is to
  70.  * forbid running additional servers (like those started from
  71.  * the test suite) if the user is already running one.
  72.  *
  73.  * XXX
  74.  * This does not solve nor prevent two servers from being
  75.  * started at the same time and running recovery at the same
  76.  * time on the same environments.
  77.  */
  78. if ((cl = clnt_create("localhost",
  79.     DB_RPC_SERVERPROG, DB_RPC_SERVERVERS, "tcp")) != NULL) {
  80. fprintf(stderr,
  81.     "%s: Berkeley DB RPC server already running.n", prog);
  82. clnt_destroy(cl);
  83. return (EXIT_FAILURE);
  84. }
  85. LIST_INIT(&__dbsrv_home);
  86. while ((ch = getopt(argc, argv, "h:I:L:P:t:T:Vv")) != EOF)
  87. switch (ch) {
  88. case 'h':
  89. (void)add_home(optarg);
  90. break;
  91. case 'I':
  92. if (__db_getlong(NULL, prog,
  93.     optarg, 1, LONG_MAX, &__dbsrv_idleto))
  94. return (EXIT_FAILURE);
  95. break;
  96. case 'L':
  97. logfile = optarg;
  98. break;
  99. case 'P':
  100. passwd = strdup(optarg);
  101. memset(optarg, 0, strlen(optarg));
  102. if (passwd == NULL) {
  103. fprintf(stderr, "%s: strdup: %sn",
  104.     prog, strerror(errno));
  105. return (EXIT_FAILURE);
  106. }
  107. if ((ret = add_passwd(passwd)) != 0) {
  108. fprintf(stderr, "%s: strdup: %sn",
  109.     prog, strerror(ret));
  110. return (EXIT_FAILURE);
  111. }
  112. break;
  113. case 't':
  114. if (__db_getlong(NULL, prog,
  115.     optarg, 1, LONG_MAX, &__dbsrv_defto))
  116. return (EXIT_FAILURE);
  117. break;
  118. case 'T':
  119. if (__db_getlong(NULL, prog,
  120.     optarg, 1, LONG_MAX, &__dbsrv_maxto))
  121. return (EXIT_FAILURE);
  122. break;
  123. case 'V':
  124. printf("%sn", db_version(NULL, NULL, NULL));
  125. return (EXIT_SUCCESS);
  126. case 'v':
  127. __dbsrv_verbose = 1;
  128. break;
  129. default:
  130. usage(prog);
  131. }
  132. /*
  133.  * Check default timeout against maximum timeout
  134.  */
  135. if (__dbsrv_defto > __dbsrv_maxto)
  136. __dbsrv_defto = __dbsrv_maxto;
  137. /*
  138.  * Check default timeout against idle timeout
  139.  * It would be bad to timeout environments sooner than txns.
  140.  */
  141. if (__dbsrv_defto > __dbsrv_idleto)
  142. fprintf(stderr,
  143.     "%s: WARNING: Idle timeout %ld is less than resource timeout %ldn",
  144.     prog, __dbsrv_idleto, __dbsrv_defto);
  145. LIST_INIT(&__dbsrv_head);
  146. /*
  147.  * If a client crashes during an RPC, our reply to it
  148.  * generates a SIGPIPE.  Ignore SIGPIPE so we don't exit unnecessarily.
  149.  */
  150. #ifdef SIGPIPE
  151. signal(SIGPIPE, SIG_IGN);
  152. #endif
  153. if (logfile != NULL && __db_util_logset("berkeley_db_svc", logfile))
  154. return (EXIT_FAILURE);
  155. /*
  156.  * Now that we are ready to start, run recovery on all the
  157.  * environments specified.
  158.  */
  159. if (env_recover(prog) != 0)
  160. return (EXIT_FAILURE);
  161. /*
  162.  * We've done our setup, now call the generated server loop
  163.  */
  164. if (__dbsrv_verbose)
  165. printf("%s:  Ready to receive requestsn", prog);
  166. __dbsrv_main();
  167. /* NOTREACHED */
  168. abort();
  169. }
  170. static void
  171. usage(char *prog)
  172. {
  173. fprintf(stderr, "usage: %s %snt%sn", prog,
  174.     "[-Vv] [-h home] [-P passwd]",
  175.     "[-I idletimeout] [-L logfile] [-t def_timeout] [-T maxtimeout]");
  176. exit(EXIT_FAILURE);
  177. }
  178. static void
  179. version_check()
  180. {
  181. int v_major, v_minor, v_patch;
  182. /* Make sure we're loaded with the right version of the DB library. */
  183. (void)db_version(&v_major, &v_minor, &v_patch);
  184. if (v_major != DB_VERSION_MAJOR ||
  185.     v_minor != DB_VERSION_MINOR || v_patch != DB_VERSION_PATCH) {
  186. fprintf(stderr,
  187. "%s: version %d.%d.%d doesn't match library version %d.%d.%dn",
  188.     prog, DB_VERSION_MAJOR, DB_VERSION_MINOR,
  189.     DB_VERSION_PATCH, v_major, v_minor, v_patch);
  190. exit(EXIT_FAILURE);
  191. }
  192. }
  193. extern "C" void
  194. __dbsrv_settimeout(
  195. ct_entry *ctp,
  196. u_int32_t to)
  197. {
  198. if (to > (u_int32_t)__dbsrv_maxto)
  199. ctp->ct_timeout = __dbsrv_maxto;
  200. else if (to <= 0)
  201. ctp->ct_timeout = __dbsrv_defto;
  202. else
  203. ctp->ct_timeout = to;
  204. }
  205. extern "C" void
  206. __dbsrv_timeout(int force)
  207. {
  208. static long to_hint = -1;
  209. time_t t;
  210. long to;
  211. ct_entry *ctp, *nextctp;
  212. if ((t = time(NULL)) == -1)
  213. return;
  214. /*
  215.  * Check hint.  If hint is further in the future
  216.  * than now, no work to do.
  217.  */
  218. if (!force && to_hint > 0 && t < to_hint)
  219. return;
  220. to_hint = -1;
  221. /*
  222.  * Timeout transactions or cursors holding DB resources.
  223.  * Do this before timing out envs to properly release resources.
  224.  *
  225.  * !!!
  226.  * We can just loop through this list looking for cursors and txns.
  227.  * We do not need to verify txn and cursor relationships at this
  228.  * point because we maintain the list in LIFO order *and* we
  229.  * maintain activity in the ultimate txn parent of any cursor
  230.  * so either everything in a txn is timing out, or nothing.
  231.  * So, since we are LIFO, we will correctly close/abort all the
  232.  * appropriate handles, in the correct order.
  233.  */
  234. for (ctp = LIST_FIRST(&__dbsrv_head); ctp != NULL; ctp = nextctp) {
  235. nextctp = LIST_NEXT(ctp, entries);
  236. switch (ctp->ct_type) {
  237. case CT_TXN:
  238. to = *(ctp->ct_activep) + ctp->ct_timeout;
  239. /* TIMEOUT */
  240. if (to < t) {
  241. if (__dbsrv_verbose)
  242. printf("Timing out txn id %ldn",
  243.     ctp->ct_id);
  244. (void)((DbTxn *)ctp->ct_anyp)->abort();
  245. __dbdel_ctp(ctp);
  246. /*
  247.  * If we timed out an txn, we may have closed
  248.  * all sorts of ctp's.
  249.  * So start over with a guaranteed good ctp.
  250.  */
  251. nextctp = LIST_FIRST(&__dbsrv_head);
  252. } else if ((to_hint > 0 && to_hint > to) ||
  253.     to_hint == -1)
  254. to_hint = to;
  255. break;
  256. case CT_CURSOR:
  257. case (CT_JOINCUR | CT_CURSOR):
  258. to = *(ctp->ct_activep) + ctp->ct_timeout;
  259. /* TIMEOUT */
  260. if (to < t) {
  261. if (__dbsrv_verbose)
  262. printf("Timing out cursor %ldn",
  263.     ctp->ct_id);
  264. (void)__dbc_close_int(ctp);
  265. /*
  266.  * Start over with a guaranteed good ctp.
  267.  */
  268. nextctp = LIST_FIRST(&__dbsrv_head);
  269. } else if ((to_hint > 0 && to_hint > to) ||
  270.     to_hint == -1)
  271. to_hint = to;
  272. break;
  273. default:
  274. break;
  275. }
  276. }
  277. /*
  278.  * Timeout idle handles.
  279.  * If we are forcing a timeout, we'll close all env handles.
  280.  */
  281. for (ctp = LIST_FIRST(&__dbsrv_head); ctp != NULL; ctp = nextctp) {
  282. nextctp = LIST_NEXT(ctp, entries);
  283. if (ctp->ct_type != CT_ENV)
  284. continue;
  285. to = *(ctp->ct_activep) + ctp->ct_idle;
  286. /* TIMEOUT */
  287. if (to < t || force) {
  288. if (__dbsrv_verbose)
  289. printf("Timing out env id %ldn", ctp->ct_id);
  290. (void)__dbenv_close_int(ctp->ct_id, 0, 1);
  291. /*
  292.  * If we timed out an env, we may have closed
  293.  * all sorts of ctp's (maybe even all of them.
  294.  * So start over with a guaranteed good ctp.
  295.  */
  296. nextctp = LIST_FIRST(&__dbsrv_head);
  297. }
  298. }
  299. }
  300. /*
  301.  * RECURSIVE FUNCTION.  We need to clear/free any number of levels of nested
  302.  * layers.
  303.  */
  304. static void
  305. __dbclear_child(ct_entry *parent)
  306. {
  307. ct_entry *ctp, *nextctp;
  308. for (ctp = LIST_FIRST(&__dbsrv_head); ctp != NULL;
  309.     ctp = nextctp) {
  310. nextctp = LIST_NEXT(ctp, entries);
  311. if (ctp->ct_type == 0)
  312. continue;
  313. if (ctp->ct_parent == parent) {
  314. __dbclear_child(ctp);
  315. /*
  316.  * Need to do this here because le_next may
  317.  * have changed with the recursive call and we
  318.  * don't want to point to a removed entry.
  319.  */
  320. nextctp = LIST_NEXT(ctp, entries);
  321. __dbclear_ctp(ctp);
  322. }
  323. }
  324. }
  325. extern "C" void
  326. __dbclear_ctp(ct_entry *ctp)
  327. {
  328. LIST_REMOVE(ctp, entries);
  329. __os_free(NULL, ctp);
  330. }
  331. extern "C" void
  332. __dbdel_ctp(ct_entry *parent)
  333. {
  334. __dbclear_child(parent);
  335. __dbclear_ctp(parent);
  336. }
  337. extern "C" ct_entry *
  338. new_ct_ent(int *errp)
  339. {
  340. time_t t;
  341. ct_entry *ctp, *octp;
  342. int ret;
  343. if ((ret = __os_malloc(NULL, sizeof(ct_entry), &ctp)) != 0) {
  344. *errp = ret;
  345. return (NULL);
  346. }
  347. memset(ctp, 0, sizeof(ct_entry));
  348. /*
  349.  * Get the time as ID.  We may service more than one request per
  350.  * second however.  If we are, then increment id value until we
  351.  * find an unused one.  We insert entries in LRU fashion at the
  352.  * head of the list.  So, if the first entry doesn't match, then
  353.  * we know for certain that we can use our entry.
  354.  */
  355. if ((t = time(NULL)) == -1) {
  356. *errp = __os_get_errno();
  357. __os_free(NULL, ctp);
  358. return (NULL);
  359. }
  360. octp = LIST_FIRST(&__dbsrv_head);
  361. if (octp != NULL && octp->ct_id >= t)
  362. t = octp->ct_id + 1;
  363. ctp->ct_id = t;
  364. ctp->ct_idle = __dbsrv_idleto;
  365. ctp->ct_activep = &ctp->ct_active;
  366. ctp->ct_origp = NULL;
  367. ctp->ct_refcount = 1;
  368. LIST_INSERT_HEAD(&__dbsrv_head, ctp, entries);
  369. return (ctp);
  370. }
  371. extern "C" ct_entry *
  372. get_tableent(long id)
  373. {
  374. ct_entry *ctp;
  375. for (ctp = LIST_FIRST(&__dbsrv_head); ctp != NULL;
  376.     ctp = LIST_NEXT(ctp, entries))
  377. if (ctp->ct_id == id)
  378. return (ctp);
  379. return (NULL);
  380. }
  381. extern "C" ct_entry *
  382. __dbsrv_sharedb(ct_entry *db_ctp, const char *name, const char *subdb, DBTYPE type, u_int32_t flags)
  383. {
  384. ct_entry *ctp;
  385. /*
  386.  * Check if we can share a db handle.  Criteria for sharing are:
  387.  * If any of the non-sharable flags are set, we cannot share.
  388.  * Must be a db ctp, obviously.
  389.  * Must share the same env parent.
  390.  * Must be the same type, or current one DB_UNKNOWN.
  391.  * Must be same byteorder, or current one must not care.
  392.  * All flags must match.
  393.  * Must be same name, but don't share in-memory databases.
  394.  * Must be same subdb name.
  395.  */
  396. if (flags & DB_SERVER_DBNOSHARE)
  397. return (NULL);
  398. for (ctp = LIST_FIRST(&__dbsrv_head); ctp != NULL;
  399.     ctp = LIST_NEXT(ctp, entries)) {
  400. /*
  401.  * Skip ourselves.
  402.  */
  403. if (ctp == db_ctp)
  404. continue;
  405. if (ctp->ct_type != CT_DB)
  406. continue;
  407. if (ctp->ct_envparent != db_ctp->ct_envparent)
  408. continue;
  409. if (type != DB_UNKNOWN && ctp->ct_dbdp.type != type)
  410. continue;
  411. if (ctp->ct_dbdp.dbflags != LF_ISSET(DB_SERVER_DBFLAGS))
  412. continue;
  413. if (db_ctp->ct_dbdp.setflags != 0 &&
  414.     ctp->ct_dbdp.setflags != db_ctp->ct_dbdp.setflags)
  415. continue;
  416. if (name == NULL || ctp->ct_dbdp.db == NULL ||
  417.     strcmp(name, ctp->ct_dbdp.db) != 0)
  418. continue;
  419. if (subdb != ctp->ct_dbdp.subdb &&
  420.     (subdb == NULL || ctp->ct_dbdp.subdb == NULL ||
  421.     strcmp(subdb, ctp->ct_dbdp.subdb) != 0))
  422. continue;
  423. /*
  424.  * If we get here, then we match.
  425.  */
  426. ctp->ct_refcount++;
  427. return (ctp);
  428. }
  429. return (NULL);
  430. }
  431. extern "C" ct_entry *
  432. __dbsrv_shareenv(ct_entry *env_ctp, home_entry *home, u_int32_t flags)
  433. {
  434. ct_entry *ctp;
  435. /*
  436.  * Check if we can share an env.  Criteria for sharing are:
  437.  * Must be an env ctp, obviously.
  438.  * Must share the same home env.
  439.  * All flags must match.
  440.  */
  441. for (ctp = LIST_FIRST(&__dbsrv_head); ctp != NULL;
  442.     ctp = LIST_NEXT(ctp, entries)) {
  443. /*
  444.  * Skip ourselves.
  445.  */
  446. if (ctp == env_ctp)
  447. continue;
  448. if (ctp->ct_type != CT_ENV)
  449. continue;
  450. if (ctp->ct_envdp.home != home)
  451. continue;
  452. if (ctp->ct_envdp.envflags != flags)
  453. continue;
  454. if (ctp->ct_envdp.onflags != env_ctp->ct_envdp.onflags)
  455. continue;
  456. if (ctp->ct_envdp.offflags != env_ctp->ct_envdp.offflags)
  457. continue;
  458. /*
  459.  * If we get here, then we match.  The only thing left to
  460.  * check is the timeout.  Since the server timeout set by
  461.  * the client is a hint, for sharing we'll give them the
  462.  * benefit of the doubt and grant them the longer timeout.
  463.  */
  464. if (ctp->ct_timeout < env_ctp->ct_timeout)
  465. ctp->ct_timeout = env_ctp->ct_timeout;
  466. ctp->ct_refcount++;
  467. return (ctp);
  468. }
  469. return (NULL);
  470. }
  471. extern "C" void
  472. __dbsrv_active(ct_entry *ctp)
  473. {
  474. time_t t;
  475. ct_entry *envctp;
  476. if (ctp == NULL)
  477. return;
  478. if ((t = time(NULL)) == -1)
  479. return;
  480. *(ctp->ct_activep) = t;
  481. if ((envctp = ctp->ct_envparent) == NULL)
  482. return;
  483. *(envctp->ct_activep) = t;
  484. return;
  485. }
  486. extern "C" int
  487. __db_close_int(long id, u_int32_t flags)
  488. {
  489. Db *dbp;
  490. int ret;
  491. ct_entry *ctp;
  492. ret = 0;
  493. ctp = get_tableent(id);
  494. if (ctp == NULL)
  495. return (DB_NOSERVER_ID);
  496. DB_ASSERT(ctp->ct_type == CT_DB);
  497. if (__dbsrv_verbose && ctp->ct_refcount != 1)
  498. printf("Deref'ing dbp id %ld, refcount %dn",
  499.     id, ctp->ct_refcount);
  500. if (--ctp->ct_refcount != 0)
  501. return (ret);
  502. dbp = ctp->ct_dbp;
  503. if (__dbsrv_verbose)
  504. printf("Closing dbp id %ldn", id);
  505. ret = dbp->close(flags);
  506. __dbdel_ctp(ctp);
  507. return (ret);
  508. }
  509. extern "C" int
  510. __dbc_close_int(ct_entry *dbc_ctp)
  511. {
  512. Dbc *dbc;
  513. int ret;
  514. ct_entry *ctp;
  515. dbc = (Dbc *)dbc_ctp->ct_anyp;
  516. ret = dbc->close();
  517. /*
  518.  * If this cursor is a join cursor then we need to fix up the
  519.  * cursors that it was joined from so that they are independent again.
  520.  */
  521. if (dbc_ctp->ct_type & CT_JOINCUR)
  522. for (ctp = LIST_FIRST(&__dbsrv_head); ctp != NULL;
  523.     ctp = LIST_NEXT(ctp, entries)) {
  524. /*
  525.  * Test if it is a join cursor, and if it is part
  526.  * of this one.
  527.  */
  528. if ((ctp->ct_type & CT_JOIN) &&
  529.     ctp->ct_activep == &dbc_ctp->ct_active) {
  530. ctp->ct_type &= ~CT_JOIN;
  531. ctp->ct_activep = ctp->ct_origp;
  532. __dbsrv_active(ctp);
  533. }
  534. }
  535. __dbclear_ctp(dbc_ctp);
  536. return (ret);
  537. }
  538. extern "C" int
  539. __dbenv_close_int(long id, u_int32_t flags, int force)
  540. {
  541. DbEnv *dbenv;
  542. int ret;
  543. ct_entry *ctp;
  544. ret = 0;
  545. ctp = get_tableent(id);
  546. if (ctp == NULL)
  547. return (DB_NOSERVER_ID);
  548. DB_ASSERT(ctp->ct_type == CT_ENV);
  549. if (__dbsrv_verbose && ctp->ct_refcount != 1)
  550. printf("Deref'ing env id %ld, refcount %dn",
  551.     id, ctp->ct_refcount);
  552. /*
  553.  * If we are timing out, we need to force the close, no matter
  554.  * what the refcount.
  555.  */
  556. if (--ctp->ct_refcount != 0 && !force)
  557. return (ret);
  558. dbenv = ctp->ct_envp;
  559. if (__dbsrv_verbose)
  560. printf("Closing env id %ldn", id);
  561. ret = dbenv->close(flags);
  562. __dbdel_ctp(ctp);
  563. return (ret);
  564. }
  565. static int
  566. add_home(char *home)
  567. {
  568. home_entry *hp, *homep;
  569. int ret;
  570. if ((ret = __os_malloc(NULL, sizeof(home_entry), &hp)) != 0)
  571. return (ret);
  572. if ((ret = __os_malloc(NULL, strlen(home)+1, &hp->home)) != 0)
  573. return (ret);
  574. memcpy(hp->home, home, strlen(home)+1);
  575. hp->dir = home;
  576. hp->passwd = NULL;
  577. /*
  578.  * This loop is to remove any trailing path separators,
  579.  * to assure hp->name points to the last component.
  580.  */
  581. hp->name = __db_rpath(home);
  582. *(hp->name) = '';
  583. hp->name++;
  584. while (*(hp->name) == '') {
  585. hp->name = __db_rpath(home);
  586. *(hp->name) = '';
  587. hp->name++;
  588. }
  589. /*
  590.  * Now we have successfully added it.  Make sure there are no
  591.  * identical names.
  592.  */
  593. for (homep = LIST_FIRST(&__dbsrv_home); homep != NULL;
  594.     homep = LIST_NEXT(homep, entries))
  595. if (strcmp(homep->name, hp->name) == 0) {
  596. printf("Already added home name %s, at directory %sn",
  597.     hp->name, homep->dir);
  598. return (-1);
  599. }
  600. LIST_INSERT_HEAD(&__dbsrv_home, hp, entries);
  601. if (__dbsrv_verbose)
  602. printf("Added home %s in dir %sn", hp->name, hp->dir);
  603. return (0);
  604. }
  605. static int
  606. add_passwd(char *passwd)
  607. {
  608. home_entry *hp;
  609. /*
  610.  * We add the passwd to the last given home dir.  If there
  611.  * isn't a home dir, or the most recent one already has a
  612.  * passwd, then there is a user error.
  613.  */
  614. hp = LIST_FIRST(&__dbsrv_home);
  615. if (hp == NULL || hp->passwd != NULL)
  616. return (EINVAL);
  617. /*
  618.  * We've already strdup'ed the passwd above, so we don't need
  619.  * to malloc new space, just point to it.
  620.  */
  621. hp->passwd = passwd;
  622. return (0);
  623. }
  624. extern "C" home_entry *
  625. get_home(char *name)
  626. {
  627. home_entry *hp;
  628. for (hp = LIST_FIRST(&__dbsrv_home); hp != NULL;
  629.     hp = LIST_NEXT(hp, entries))
  630. if (strcmp(name, hp->name) == 0)
  631. return (hp);
  632. return (NULL);
  633. }
  634. static int
  635. env_recover(char *progname)
  636. {
  637. DbEnv *dbenv;
  638. home_entry *hp;
  639. u_int32_t flags;
  640. int exitval, ret;
  641. for (hp = LIST_FIRST(&__dbsrv_home); hp != NULL;
  642.     hp = LIST_NEXT(hp, entries)) {
  643. exitval = 0;
  644. dbenv = new DbEnv(DB_CXX_NO_EXCEPTIONS);
  645. if (__dbsrv_verbose == 1) {
  646. (void)dbenv->set_verbose(DB_VERB_RECOVERY, 1);
  647. (void)dbenv->set_verbose(DB_VERB_CHKPOINT, 1);
  648. }
  649. dbenv->set_errfile(stderr);
  650. dbenv->set_errpfx(progname);
  651. if (hp->passwd != NULL)
  652. (void)dbenv->set_encrypt(hp->passwd, DB_ENCRYPT_AES);
  653. /*
  654.  * Initialize the env with DB_RECOVER.  That is all we
  655.  * have to do to run recovery.
  656.  */
  657. if (__dbsrv_verbose)
  658. printf("Running recovery on %sn", hp->home);
  659. flags = DB_CREATE | DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_MPOOL |
  660.     DB_INIT_TXN | DB_USE_ENVIRON | DB_RECOVER;
  661. if ((ret = dbenv->open(hp->home, flags, 0)) != 0) {
  662. dbenv->err(ret, "DbEnv->open");
  663. goto error;
  664. }
  665. if (0) {
  666. error: exitval = 1;
  667. }
  668. if ((ret = dbenv->close(0)) != 0) {
  669. exitval = 1;
  670. fprintf(stderr, "%s: dbenv->close: %sn",
  671.     progname, db_strerror(ret));
  672. }
  673. if (exitval)
  674. return (exitval);
  675. }
  676. return (0);
  677. }