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

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