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

MySQL数据库

开发平台:

Visual C++

  1. /*-
  2.  * See the file LICENSE for redistribution information.
  3.  *
  4.  * Copyright (c) 1996-2002
  5.  * Sleepycat Software.  All rights reserved.
  6.  */
  7. #include "db_config.h"
  8. #ifndef lint
  9. static const char revid[] = "$Id: env_open.c,v 11.111 2002/09/03 01:20:51 mjc Exp $";
  10. #endif /* not lint */
  11. #ifndef NO_SYSTEM_INCLUDES
  12. #include <sys/types.h>
  13. #include <ctype.h>
  14. #include <stdlib.h>
  15. #include <string.h>
  16. #include <unistd.h>
  17. #endif
  18. #include "db_int.h"
  19. #include "dbinc/crypto.h"
  20. #include "dbinc/db_page.h"
  21. #include "dbinc/db_shash.h"
  22. #include "dbinc/btree.h"
  23. #include "dbinc/hash.h"
  24. #include "dbinc/lock.h"
  25. #include "dbinc/log.h"
  26. #include "dbinc/mp.h"
  27. #include "dbinc/qam.h"
  28. #include "dbinc/rep.h"
  29. #include "dbinc/txn.h"
  30. #include "dbinc/fop.h"
  31. static int __db_parse __P((DB_ENV *, char *));
  32. static int __db_tmp_open __P((DB_ENV *, u_int32_t, char *, DB_FH *));
  33. static int __dbenv_config __P((DB_ENV *, const char *, u_int32_t));
  34. static int __dbenv_iremove __P((DB_ENV *, const char *, u_int32_t));
  35. static int __dbenv_refresh __P((DB_ENV *, u_int32_t));
  36. /*
  37.  * db_version --
  38.  * Return version information.
  39.  *
  40.  * EXTERN: char *db_version __P((int *, int *, int *));
  41.  */
  42. char *
  43. db_version(majverp, minverp, patchp)
  44. int *majverp, *minverp, *patchp;
  45. {
  46. if (majverp != NULL)
  47. *majverp = DB_VERSION_MAJOR;
  48. if (minverp != NULL)
  49. *minverp = DB_VERSION_MINOR;
  50. if (patchp != NULL)
  51. *patchp = DB_VERSION_PATCH;
  52. return ((char *)DB_VERSION_STRING);
  53. }
  54. /*
  55.  * __dbenv_open --
  56.  * Initialize an environment.
  57.  *
  58.  * PUBLIC: int __dbenv_open __P((DB_ENV *, const char *, u_int32_t, int));
  59.  */
  60. int
  61. __dbenv_open(dbenv, db_home, flags, mode)
  62. DB_ENV *dbenv;
  63. const char *db_home;
  64. u_int32_t flags;
  65. int mode;
  66. {
  67. DB_MPOOL *dbmp;
  68. int ret;
  69. u_int32_t init_flags, orig_flags;
  70. orig_flags = dbenv->flags;
  71. #undef OKFLAGS
  72. #define OKFLAGS
  73. DB_CREATE | DB_INIT_CDB | DB_INIT_LOCK | DB_INIT_LOG |
  74. DB_INIT_MPOOL | DB_INIT_TXN | DB_JOINENV | DB_LOCKDOWN |
  75. DB_PRIVATE | DB_RECOVER | DB_RECOVER_FATAL | DB_SYSTEM_MEM |
  76. DB_THREAD | DB_USE_ENVIRON | DB_USE_ENVIRON_ROOT
  77. #undef OKFLAGS_CDB
  78. #define OKFLAGS_CDB
  79. DB_CREATE | DB_INIT_CDB | DB_INIT_MPOOL | DB_LOCKDOWN |
  80. DB_PRIVATE | DB_SYSTEM_MEM | DB_THREAD |
  81. DB_USE_ENVIRON | DB_USE_ENVIRON_ROOT
  82. /*
  83.  * Flags saved in the init_flags field of the environment, representing
  84.  * flags to DB_ENV->set_flags and DB_ENV->open that need to be set.
  85.  */
  86. #define DB_INITENV_CDB 0x0001 /* DB_INIT_CDB */
  87. #define DB_INITENV_CDB_ALLDB 0x0002 /* DB_INIT_CDB_ALLDB */
  88. #define DB_INITENV_LOCK 0x0004 /* DB_INIT_LOCK */
  89. #define DB_INITENV_LOG 0x0008 /* DB_INIT_LOG */
  90. #define DB_INITENV_MPOOL 0x0010 /* DB_INIT_MPOOL */
  91. #define DB_INITENV_TXN 0x0020 /* DB_INIT_TXN */
  92. if ((ret = __db_fchk(dbenv, "DB_ENV->open", flags, OKFLAGS)) != 0)
  93. return (ret);
  94. if (LF_ISSET(DB_INIT_CDB) &&
  95.     (ret = __db_fchk(dbenv, "DB_ENV->open", flags, OKFLAGS_CDB)) != 0)
  96. return (ret);
  97. if ((ret = __db_fcchk(dbenv,
  98.     "DB_ENV->open", flags, DB_PRIVATE, DB_SYSTEM_MEM)) != 0)
  99. return (ret);
  100. if ((ret = __db_fcchk(dbenv,
  101.     "DB_ENV->open", flags, DB_RECOVER, DB_RECOVER_FATAL)) != 0)
  102. return (ret);
  103. if ((ret = __db_fcchk(dbenv, "DB_ENV->open", flags, DB_JOINENV,
  104.     DB_CREATE | DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_MPOOL |
  105.     DB_INIT_TXN | DB_PRIVATE)) != 0)
  106. return (ret);
  107. /*
  108.  * Currently we support one kind of mutex that is intra-process only,
  109.  * POSIX 1003.1 pthreads, because a variety of systems don't support
  110.  * the full pthreads API, and our only alternative is test-and-set.
  111.  */
  112. #ifdef HAVE_MUTEX_THREAD_ONLY
  113. if (!LF_ISSET(DB_PRIVATE)) {
  114. __db_err(dbenv,
  115.     "Berkeley DB library configured to support only DB_PRIVATE environments");
  116. return (EINVAL);
  117. }
  118. #endif
  119. /*
  120.  * If we're doing recovery, destroy the environment so that we create
  121.  * all the regions from scratch.  I'd like to reuse already created
  122.  * regions, but that's hard.  We would have to create the environment
  123.  * region from scratch, at least, as we have no way of knowing if its
  124.  * linked lists are corrupted.
  125.  *
  126.  * I suppose we could set flags while modifying those links, but that
  127.  * is going to be difficult to get right.  The major concern I have
  128.  * is if the application stomps the environment with a rogue pointer.
  129.  * We have no way of detecting that, and we could be forced into a
  130.  * situation where we start up and then crash, repeatedly.
  131.  *
  132.  * Note that we do not check any flags like DB_PRIVATE before calling
  133.  * remove.  We don't care if the current environment was private or
  134.  * not, we just want to nail any files that are left-over for whatever
  135.  * reason, from whatever session.
  136.  */
  137. if (LF_ISSET(DB_RECOVER | DB_RECOVER_FATAL))
  138. if ((ret = __dbenv_iremove(dbenv, db_home, DB_FORCE)) != 0 ||
  139.     (ret = __dbenv_refresh(dbenv, orig_flags)) != 0)
  140. return (ret);
  141. /* Initialize the DB_ENV structure. */
  142. if ((ret = __dbenv_config(dbenv, db_home, flags)) != 0)
  143. goto err;
  144. /* Convert the DB_ENV->open flags to internal flags. */
  145. if (LF_ISSET(DB_CREATE))
  146. F_SET(dbenv, DB_ENV_CREATE);
  147. if (LF_ISSET(DB_LOCKDOWN))
  148. F_SET(dbenv, DB_ENV_LOCKDOWN);
  149. if (LF_ISSET(DB_PRIVATE))
  150. F_SET(dbenv, DB_ENV_PRIVATE);
  151. if (LF_ISSET(DB_RECOVER_FATAL))
  152. F_SET(dbenv, DB_ENV_FATAL);
  153. if (LF_ISSET(DB_SYSTEM_MEM))
  154. F_SET(dbenv, DB_ENV_SYSTEM_MEM);
  155. if (LF_ISSET(DB_THREAD))
  156. F_SET(dbenv, DB_ENV_THREAD);
  157. /* Default permissions are read-write for both owner and group. */
  158. dbenv->db_mode = mode == 0 ? __db_omode("rwrw--") : mode;
  159. /*
  160.  * Create/join the environment.  We pass in the flags that
  161.  * will be of interest to an environment joining later;  if
  162.  * we're not the ones to do the create, we
  163.  * pull out whatever has been stored, if we don't do a create.
  164.  */
  165. init_flags = 0;
  166. init_flags |= (LF_ISSET(DB_INIT_CDB) ? DB_INITENV_CDB : 0);
  167. init_flags |= (LF_ISSET(DB_INIT_LOCK) ? DB_INITENV_LOCK : 0);
  168. init_flags |= (LF_ISSET(DB_INIT_LOG) ? DB_INITENV_LOG : 0);
  169. init_flags |= (LF_ISSET(DB_INIT_MPOOL) ? DB_INITENV_MPOOL : 0);
  170. init_flags |= (LF_ISSET(DB_INIT_TXN) ? DB_INITENV_TXN : 0);
  171. init_flags |=
  172.     (F_ISSET(dbenv, DB_ENV_CDB_ALLDB) ? DB_INITENV_CDB_ALLDB : 0);
  173. if ((ret = __db_e_attach(dbenv, &init_flags)) != 0)
  174. goto err;
  175. /*
  176.  * __db_e_attach will return the saved init_flags field, which
  177.  * contains the DB_INIT_* flags used when we were created.
  178.  */
  179. if (LF_ISSET(DB_JOINENV)) {
  180. LF_CLR(DB_JOINENV);
  181. LF_SET((init_flags & DB_INITENV_CDB) ? DB_INIT_CDB : 0);
  182. LF_SET((init_flags & DB_INITENV_LOCK) ? DB_INIT_LOCK : 0);
  183. LF_SET((init_flags & DB_INITENV_LOG) ? DB_INIT_LOG : 0);
  184. LF_SET((init_flags & DB_INITENV_MPOOL) ? DB_INIT_MPOOL : 0);
  185. LF_SET((init_flags & DB_INITENV_TXN) ? DB_INIT_TXN : 0);
  186. if (LF_ISSET(DB_INITENV_CDB_ALLDB) &&
  187.     (ret = dbenv->set_flags(dbenv, DB_CDB_ALLDB, 1)) != 0)
  188. goto err;
  189. }
  190. /* Initialize for CDB product. */
  191. if (LF_ISSET(DB_INIT_CDB)) {
  192. LF_SET(DB_INIT_LOCK);
  193. F_SET(dbenv, DB_ENV_CDB);
  194. }
  195. /*
  196.  * Initialize the subsystems.  Transactions imply logging but do not
  197.  * imply locking.  While almost all applications want both locking
  198.  * and logging, it would not be unreasonable for a single threaded
  199.  * process to want transactions for atomicity guarantees, but not
  200.  * necessarily need concurrency.
  201.  */
  202. if (LF_ISSET(DB_INIT_MPOOL))
  203. if ((ret = __memp_open(dbenv)) != 0)
  204. goto err;
  205. #ifdef HAVE_CRYPTO
  206. /*
  207.  * Initialize the ciphering area prior to any running of recovery so
  208.  * that we can initialize the keys, etc. before recovery.
  209.  *
  210.  * !!!
  211.  * This must be after the mpool init, but before the log initialization
  212.  * because log_open may attempt to run log_recover during its open.
  213.  */
  214. if ((ret = __crypto_region_init(dbenv)) != 0)
  215. goto err;
  216. #endif
  217. if (LF_ISSET(DB_INIT_LOG | DB_INIT_TXN))
  218. if ((ret = __log_open(dbenv)) != 0)
  219. goto err;
  220. if (LF_ISSET(DB_INIT_LOCK))
  221. if ((ret = __lock_open(dbenv)) != 0)
  222. goto err;
  223. if (LF_ISSET(DB_INIT_TXN)) {
  224. if ((ret = __txn_open(dbenv)) != 0)
  225. goto err;
  226. /*
  227.  * If the application is running with transactions, initialize
  228.  * the function tables.
  229.  */
  230. if ((ret = __bam_init_recover(dbenv, &dbenv->recover_dtab,
  231.     &dbenv->recover_dtab_size)) != 0)
  232. goto err;
  233. if ((ret = __crdel_init_recover(dbenv, &dbenv->recover_dtab,
  234.     &dbenv->recover_dtab_size)) != 0)
  235. goto err;
  236. if ((ret = __db_init_recover(dbenv, &dbenv->recover_dtab,
  237.     &dbenv->recover_dtab_size)) != 0)
  238. goto err;
  239. if ((ret = __dbreg_init_recover(dbenv, &dbenv->recover_dtab,
  240.     &dbenv->recover_dtab_size)) != 0)
  241. goto err;
  242. if ((ret = __fop_init_recover(dbenv, &dbenv->recover_dtab,
  243.     &dbenv->recover_dtab_size)) != 0)
  244. goto err;
  245. if ((ret = __ham_init_recover(dbenv, &dbenv->recover_dtab,
  246.     &dbenv->recover_dtab_size)) != 0)
  247. goto err;
  248. if ((ret = __qam_init_recover(dbenv, &dbenv->recover_dtab,
  249.     &dbenv->recover_dtab_size)) != 0)
  250. goto err;
  251. if ((ret = __txn_init_recover(dbenv, &dbenv->recover_dtab,
  252.     &dbenv->recover_dtab_size)) != 0)
  253. goto err;
  254. /* Perform recovery for any previous run. */
  255. if (LF_ISSET(DB_RECOVER | DB_RECOVER_FATAL) &&
  256.     (ret = __db_apprec(dbenv, NULL,
  257.     LF_ISSET(DB_RECOVER | DB_RECOVER_FATAL))) != 0)
  258. goto err;
  259. }
  260. /* Initialize the replication area just in case. */
  261. if ((ret = __rep_region_init(dbenv)) != 0)
  262. goto err;
  263. /*
  264.  * Initialize the DB list, and its mutex as necessary.  If the env
  265.  * handle isn't free-threaded we don't need a mutex because there
  266.  * will never be more than a single DB handle on the list.  If the
  267.  * mpool wasn't initialized, then we can't ever open a DB handle.
  268.  *
  269.  * We also need to initialize the MT mutex as necessary, so do them
  270.  * both.  If we error, __dbenv_refresh() will clean up.
  271.  *
  272.  * !!!
  273.  * This must come after the __memp_open call above because if we are
  274.  * recording mutexes for system resources, we will do it in the mpool
  275.  * region for environments and db handles.  So, the mpool region must
  276.  * already be initialized.
  277.  */
  278. LIST_INIT(&dbenv->dblist);
  279. if (F_ISSET(dbenv, DB_ENV_THREAD) && LF_ISSET(DB_INIT_MPOOL)) {
  280. dbmp = dbenv->mp_handle;
  281. if ((ret = __db_mutex_setup(
  282.     dbenv, dbmp->reginfo, &dbenv->dblist_mutexp,
  283.     MUTEX_ALLOC | MUTEX_THREAD)) != 0)
  284. goto err;
  285. if ((ret = __db_mutex_setup(
  286.     dbenv, dbmp->reginfo, &dbenv->mt_mutexp,
  287.     MUTEX_ALLOC | MUTEX_THREAD)) != 0)
  288. goto err;
  289. }
  290. /*
  291.  * If we've created the regions, are running with transactions, and did
  292.  * not just run recovery, we need to log the fact that the transaction
  293.  * IDs got reset.
  294.  *
  295.  * If we ran recovery, there may be prepared-but-not-yet-committed
  296.  * transactions that need to be resolved.  Recovery resets the minimum
  297.  * transaction ID and logs the reset if that's appropriate, so we
  298.  * don't need to do anything here in the recover case.
  299.  */
  300. if (TXN_ON(dbenv) &&
  301.     F_ISSET((REGINFO *)dbenv->reginfo, REGION_CREATE) &&
  302.     !LF_ISSET(DB_RECOVER | DB_RECOVER_FATAL) &&
  303.     (ret = __txn_reset(dbenv)) != 0)
  304. goto err;
  305. return (0);
  306. err: /* If we fail after creating the regions, remove them. */
  307. if (dbenv->reginfo != NULL &&
  308.     F_ISSET((REGINFO *)dbenv->reginfo, REGION_CREATE)) {
  309. ret = __db_panic(dbenv, ret);
  310. (void)__dbenv_refresh(dbenv, orig_flags);
  311. (void)__dbenv_iremove(dbenv, db_home, DB_FORCE);
  312. }
  313. (void)__dbenv_refresh(dbenv, orig_flags);
  314. return (ret);
  315. }
  316. /*
  317.  * __dbenv_remove --
  318.  * Discard an environment.
  319.  *
  320.  * PUBLIC: int __dbenv_remove __P((DB_ENV *, const char *, u_int32_t));
  321.  */
  322. int
  323. __dbenv_remove(dbenv, db_home, flags)
  324. DB_ENV *dbenv;
  325. const char *db_home;
  326. u_int32_t flags;
  327. {
  328. int ret, t_ret;
  329. ret = __dbenv_iremove(dbenv, db_home, flags);
  330. if ((t_ret = dbenv->close(dbenv, 0)) != 0 && ret == 0)
  331. ret = t_ret;
  332. return (ret);
  333. }
  334. /*
  335.  * __dbenv_iremove --
  336.  * Discard an environment, internal version.
  337.  */
  338. static int
  339. __dbenv_iremove(dbenv, db_home, flags)
  340. DB_ENV *dbenv;
  341. const char *db_home;
  342. u_int32_t flags;
  343. {
  344. int ret;
  345. #undef OKFLAGS
  346. #define OKFLAGS
  347. DB_FORCE | DB_USE_ENVIRON | DB_USE_ENVIRON_ROOT
  348. /* Validate arguments. */
  349. if ((ret = __db_fchk(dbenv, "DB_ENV->remove", flags, OKFLAGS)) != 0)
  350. return (ret);
  351. ENV_ILLEGAL_AFTER_OPEN(dbenv, "DB_ENV->remove");
  352. /* Initialize the DB_ENV structure. */
  353. if ((ret = __dbenv_config(dbenv, db_home, flags)) != 0)
  354. return (ret);
  355. /* Remove the environment. */
  356. return (__db_e_remove(dbenv, flags));
  357. }
  358. /*
  359.  * __dbenv_config --
  360.  * Initialize the DB_ENV structure.
  361.  */
  362. static int
  363. __dbenv_config(dbenv, db_home, flags)
  364. DB_ENV *dbenv;
  365. const char *db_home;
  366. u_int32_t flags;
  367. {
  368. FILE *fp;
  369. int ret;
  370. char *p, buf[256];
  371. /*
  372.  * Set the database home.  Do this before calling __db_appname,
  373.  * it uses the home directory.
  374.  */
  375. if ((ret = __db_home(dbenv, db_home, flags)) != 0)
  376. return (ret);
  377. /* Parse the config file. */
  378. if ((ret =
  379.     __db_appname(dbenv, DB_APP_NONE, "DB_CONFIG", 0, NULL, &p)) != 0)
  380. return (ret);
  381. fp = fopen(p, "r");
  382. __os_free(dbenv, p);
  383. if (fp != NULL) {
  384. while (fgets(buf, sizeof(buf), fp) != NULL) {
  385. if ((p = strchr(buf, 'n')) != NULL)
  386. *p = '';
  387. else if (strlen(buf) + 1 == sizeof(buf)) {
  388. __db_err(dbenv, "DB_CONFIG: line too long");
  389. (void)fclose(fp);
  390. return (EINVAL);
  391. }
  392. if (buf[0] == '' ||
  393.     buf[0] == '#' || isspace((int)buf[0]))
  394. continue;
  395. if ((ret = __db_parse(dbenv, buf)) != 0) {
  396. (void)fclose(fp);
  397. return (ret);
  398. }
  399. }
  400. (void)fclose(fp);
  401. }
  402. /*
  403.  * If no temporary directory path was specified in the config file,
  404.  * choose one.
  405.  */
  406. if (dbenv->db_tmp_dir == NULL && (ret = __os_tmpdir(dbenv, flags)) != 0)
  407. return (ret);
  408. /*
  409.  * The locking file descriptor is rarely on.  Set the fd to -1, not
  410.  * because it's ever tested, but to make sure we catch mistakes.
  411.  */
  412. if ((ret = __os_calloc(
  413.     dbenv, 1, sizeof(*dbenv->lockfhp), &dbenv->lockfhp)) != 0)
  414. return (ret);
  415. dbenv->lockfhp->fd = -1;
  416. /* Flag that the DB_ENV structure has been initialized. */
  417. F_SET(dbenv, DB_ENV_OPEN_CALLED);
  418. return (0);
  419. }
  420. /*
  421.  * __dbenv_close --
  422.  * DB_ENV destructor.
  423.  *
  424.  * PUBLIC: int __dbenv_close __P((DB_ENV *, u_int32_t));
  425.  */
  426. int
  427. __dbenv_close(dbenv, flags)
  428. DB_ENV *dbenv;
  429. u_int32_t flags;
  430. {
  431. char **p;
  432. int ret, t_ret;
  433. COMPQUIET(flags, 0);
  434. PANIC_CHECK(dbenv);
  435. ret = 0;
  436. /*
  437.  * Before checking the reference count, we have to see if we
  438.  * were in the middle of restoring transactions and need to
  439.  * close the open files.
  440.  */
  441. if (TXN_ON(dbenv) && (t_ret = __txn_preclose(dbenv)) != 0 && ret == 0)
  442. ret = t_ret;
  443. if (dbenv->rep_handle != NULL &&
  444.     (t_ret = __rep_preclose(dbenv, 1)) != 0 && ret == 0)
  445. ret = t_ret;
  446. if (dbenv->db_ref != 0) {
  447. __db_err(dbenv,
  448.     "Database handles open during environment close");
  449. if (ret == 0)
  450. ret = EINVAL;
  451. }
  452. /*
  453.  * Detach from the regions and undo the allocations done by
  454.  * DB_ENV->open.
  455.  */
  456. if ((t_ret = __dbenv_refresh(dbenv, 0)) != 0 && ret == 0)
  457. ret = t_ret;
  458. /* Do per-subsystem destruction. */
  459. __lock_dbenv_close(dbenv); /* void */
  460. if ((t_ret = __rep_dbenv_close(dbenv)) != 0 && ret == 0)
  461. ret = t_ret;
  462. #ifdef HAVE_CRYPTO
  463. if ((t_ret = __crypto_dbenv_close(dbenv)) != 0 && ret == 0)
  464. ret = t_ret;
  465. #endif
  466. /* Release any string-based configuration parameters we've copied. */
  467. if (dbenv->db_log_dir != NULL)
  468. __os_free(dbenv, dbenv->db_log_dir);
  469. if (dbenv->db_tmp_dir != NULL)
  470. __os_free(dbenv, dbenv->db_tmp_dir);
  471. if (dbenv->db_data_dir != NULL) {
  472. for (p = dbenv->db_data_dir; *p != NULL; ++p)
  473. __os_free(dbenv, *p);
  474. __os_free(dbenv, dbenv->db_data_dir);
  475. }
  476. /* Discard the structure. */
  477. memset(dbenv, CLEAR_BYTE, sizeof(DB_ENV));
  478. __os_free(NULL, dbenv);
  479. return (ret);
  480. }
  481. /*
  482.  * __dbenv_refresh --
  483.  * Refresh the DB_ENV structure, releasing resources allocated by
  484.  * DB_ENV->open, and returning it to the state it was in just before
  485.  * open was called.  (Note that this means that any state set by
  486.  * pre-open configuration functions must be preserved.)
  487.  */
  488. static int
  489. __dbenv_refresh(dbenv, orig_flags)
  490. DB_ENV *dbenv;
  491. u_int32_t orig_flags;
  492. {
  493. DB_MPOOL *dbmp;
  494. int ret, t_ret;
  495. ret = 0;
  496. /*
  497.  * Close subsystems, in the reverse order they were opened (txn
  498.  * must be first, it may want to discard locks and flush the log).
  499.  *
  500.  * !!!
  501.  * Note that these functions, like all of __dbenv_refresh, only undo
  502.  * the effects of __dbenv_open.  Functions that undo work done by
  503.  * db_env_create or by a configurator function should go in
  504.  * __dbenv_close.
  505.  */
  506. if (TXN_ON(dbenv) &&
  507.     (t_ret = __txn_dbenv_refresh(dbenv)) != 0 && ret == 0)
  508. ret = t_ret;
  509. if (LOGGING_ON(dbenv) &&
  510.     (t_ret = __log_dbenv_refresh(dbenv)) != 0 && ret == 0)
  511. ret = t_ret;
  512. /*
  513.  * Locking should come after logging, because closing log results
  514.  * in files closing which may require locks being released.
  515.  */
  516. if (LOCKING_ON(dbenv) &&
  517.     (t_ret = __lock_dbenv_refresh(dbenv)) != 0 && ret == 0)
  518. ret = t_ret;
  519. /*
  520.  * Discard DB list and its mutex.
  521.  * Discard the MT mutex.
  522.  *
  523.  * !!!
  524.  * This must be done before we close the mpool region because we
  525.  * may have allocated the DB handle mutex in the mpool region.
  526.  * It must be done *after* we close the log region, though, because
  527.  * we close databases and try to acquire the mutex when we close
  528.  * log file handles.  Ick.
  529.  */
  530. LIST_INIT(&dbenv->dblist);
  531. if (dbenv->dblist_mutexp != NULL) {
  532. dbmp = dbenv->mp_handle;
  533. __db_mutex_free(dbenv, dbmp->reginfo, dbenv->dblist_mutexp);
  534. }
  535. if (dbenv->mt_mutexp != NULL) {
  536. dbmp = dbenv->mp_handle;
  537. __db_mutex_free(dbenv, dbmp->reginfo, dbenv->mt_mutexp);
  538. }
  539. if (dbenv->mt != NULL) {
  540. __os_free(dbenv, dbenv->mt);
  541. dbenv->mt = NULL;
  542. }
  543. if (MPOOL_ON(dbenv)) {
  544. /*
  545.  * If it's a private environment, flush the contents to disk.
  546.  * Recovery would have put everything back together, but it's
  547.  * faster and cleaner to flush instead.
  548.  */
  549. if (F_ISSET(dbenv, DB_ENV_PRIVATE) &&
  550.     (t_ret = dbenv->memp_sync(dbenv, NULL)) != 0 && ret == 0)
  551. ret = t_ret;
  552. if ((t_ret = __memp_dbenv_refresh(dbenv)) != 0 && ret == 0)
  553. ret = t_ret;
  554. }
  555. /* Detach from the region. */
  556. if (dbenv->reginfo != NULL) {
  557. if ((t_ret = __db_e_detach(dbenv, 0)) != 0 && ret == 0)
  558. ret = t_ret;
  559. /*
  560.  * !!!
  561.  * Don't free dbenv->reginfo or set the reference to NULL,
  562.  * that was done by __db_e_detach().
  563.  */
  564. }
  565. /* Undo changes and allocations done by __dbenv_open. */
  566. if (dbenv->db_home != NULL) {
  567. __os_free(dbenv, dbenv->db_home);
  568. dbenv->db_home = NULL;
  569. }
  570. dbenv->db_mode = 0;
  571. if (dbenv->lockfhp != NULL) {
  572. __os_free(dbenv, dbenv->lockfhp);
  573. dbenv->lockfhp = NULL;
  574. }
  575. if (dbenv->recover_dtab != NULL) {
  576. __os_free(dbenv, dbenv->recover_dtab);
  577. dbenv->recover_dtab = NULL;
  578. dbenv->recover_dtab_size = 0;
  579. }
  580. dbenv->flags = orig_flags;
  581. return (ret);
  582. }
  583. #define DB_ADDSTR(add) {
  584. if ((add) != NULL) {
  585. /* If leading slash, start over. */
  586. if (__os_abspath(add)) {
  587. p = str;
  588. slash = 0;
  589. }
  590. /* Append to the current string. */
  591. len = strlen(add);
  592. if (slash)
  593. *p++ = PATH_SEPARATOR[0];
  594. memcpy(p, add, len);
  595. p += len;
  596. slash = strchr(PATH_SEPARATOR, p[-1]) == NULL;
  597. }
  598. }
  599. /*
  600.  * __db_appname --
  601.  * Given an optional DB environment, directory and file name and type
  602.  * of call, build a path based on the DB_ENV->open rules, and return
  603.  * it in allocated space.
  604.  *
  605.  * PUBLIC: int __db_appname __P((DB_ENV *, APPNAME,
  606.  * PUBLIC:    const char *, u_int32_t, DB_FH *, char **));
  607.  */
  608. int
  609. __db_appname(dbenv, appname, file, tmp_oflags, fhp, namep)
  610. DB_ENV *dbenv;
  611. APPNAME appname;
  612. const char *file;
  613. u_int32_t tmp_oflags;
  614. DB_FH *fhp;
  615. char **namep;
  616. {
  617. size_t len, str_len;
  618. int data_entry, ret, slash, tmp_create;
  619. const char *a, *b;
  620. char *p, *str;
  621. a = b = NULL;
  622. data_entry = -1;
  623. tmp_create = 0;
  624. /*
  625.  * We don't return a name when creating temporary files, just a file
  626.  * handle.  Default to an error now.
  627.  */
  628. if (fhp != NULL)
  629. F_CLR(fhp, DB_FH_VALID);
  630. if (namep != NULL)
  631. *namep = NULL;
  632. /*
  633.  * Absolute path names are never modified.  If the file is an absolute
  634.  * path, we're done.
  635.  */
  636. if (file != NULL && __os_abspath(file))
  637. return (__os_strdup(dbenv, file, namep));
  638. /* Everything else is relative to the environment home. */
  639. if (dbenv != NULL)
  640. a = dbenv->db_home;
  641. retry: /*
  642.  * DB_APP_NONE:
  643.  *      DB_HOME/file
  644.  * DB_APP_DATA:
  645.  *      DB_HOME/DB_DATA_DIR/file
  646.  * DB_APP_LOG:
  647.  *      DB_HOME/DB_LOG_DIR/file
  648.  * DB_APP_TMP:
  649.  *      DB_HOME/DB_TMP_DIR/<create>
  650.  */
  651. switch (appname) {
  652. case DB_APP_NONE:
  653. break;
  654. case DB_APP_DATA:
  655. if (dbenv != NULL && dbenv->db_data_dir != NULL &&
  656.     (b = dbenv->db_data_dir[++data_entry]) == NULL) {
  657. data_entry = -1;
  658. b = dbenv->db_data_dir[0];
  659. }
  660. break;
  661. case DB_APP_LOG:
  662. if (dbenv != NULL)
  663. b = dbenv->db_log_dir;
  664. break;
  665. case DB_APP_TMP:
  666. if (dbenv != NULL)
  667. b = dbenv->db_tmp_dir;
  668. tmp_create = 1;
  669. break;
  670. }
  671. len =
  672.     (a == NULL ? 0 : strlen(a) + 1) +
  673.     (b == NULL ? 0 : strlen(b) + 1) +
  674.     (file == NULL ? 0 : strlen(file) + 1);
  675. /*
  676.  * Allocate space to hold the current path information, as well as any
  677.  * temporary space that we're going to need to create a temporary file
  678.  * name.
  679.  */
  680. #define DB_TRAIL "BDBXXXXXX"
  681. str_len = len + sizeof(DB_TRAIL) + 10;
  682. if ((ret = __os_malloc(dbenv, str_len, &str)) != 0)
  683. return (ret);
  684. slash = 0;
  685. p = str;
  686. DB_ADDSTR(a);
  687. DB_ADDSTR(b);
  688. DB_ADDSTR(file);
  689. *p = '';
  690. /*
  691.  * If we're opening a data file, see if it exists.  If it does,
  692.  * return it, otherwise, try and find another one to open.
  693.  */
  694. if (__os_exists(str, NULL) != 0 && data_entry != -1) {
  695. __os_free(dbenv, str);
  696. b = NULL;
  697. goto retry;
  698. }
  699. /* Create the file if so requested. */
  700. if (tmp_create &&
  701.     (ret = __db_tmp_open(dbenv, tmp_oflags, str, fhp)) != 0) {
  702. __os_free(dbenv, str);
  703. return (ret);
  704. }
  705. if (namep == NULL)
  706. __os_free(dbenv, str);
  707. else
  708. *namep = str;
  709. return (0);
  710. }
  711. /*
  712.  * __db_home --
  713.  * Find the database home.
  714.  *
  715.  * PUBLIC: int __db_home __P((DB_ENV *, const char *, u_int32_t));
  716.  */
  717. int
  718. __db_home(dbenv, db_home, flags)
  719. DB_ENV *dbenv;
  720. const char *db_home;
  721. u_int32_t flags;
  722. {
  723. const char *p;
  724. /*
  725.  * Use db_home by default, this allows utilities to reasonably
  726.  * override the environment either explicitly or by using a -h
  727.  * option.  Otherwise, use the environment if it's permitted
  728.  * and initialized.
  729.  */
  730. if ((p = db_home) == NULL &&
  731.     (LF_ISSET(DB_USE_ENVIRON) ||
  732.     (LF_ISSET(DB_USE_ENVIRON_ROOT) && __os_isroot())) &&
  733.     (p = getenv("DB_HOME")) != NULL && p[0] == '') {
  734. __db_err(dbenv, "illegal DB_HOME environment variable");
  735. return (EINVAL);
  736. }
  737. return (p == NULL ? 0 : __os_strdup(dbenv, p, &dbenv->db_home));
  738. }
  739. #define __DB_OVFL(v, max)
  740. if (v > max) {
  741. __v = v;
  742. __max = max;
  743. goto toobig;
  744. }
  745. /*
  746.  * __db_parse --
  747.  * Parse a single NAME VALUE pair.
  748.  */
  749. static int
  750. __db_parse(dbenv, s)
  751. DB_ENV *dbenv;
  752. char *s;
  753. {
  754. u_long __max, __v, v1, v2, v3;
  755. u_int32_t flags;
  756. char *name, *p, *value, v4;
  757. /*
  758.  * !!!
  759.  * The value of 40 is hard-coded into format arguments to sscanf
  760.  * below, it can't be changed here without changing it there, too.
  761.  */
  762. char arg[40];
  763. /*
  764.  * Name/value pairs are parsed as two white-space separated strings.
  765.  * Leading and trailing white-space is trimmed from the value, but
  766.  * it may contain embedded white-space.  Note: we use the isspace(3)
  767.  * macro because it's more portable, but that means that you can use
  768.  * characters like form-feed to separate the strings.
  769.  */
  770. name = s;
  771. for (p = name; *p != '' && !isspace((int)*p); ++p)
  772. ;
  773. if (*p == '' || p == name)
  774. goto illegal;
  775. *p = '';
  776. for (++p; isspace((int)*p); ++p)
  777. ;
  778. if (*p == '')
  779. goto illegal;
  780. value = p;
  781. for (++p; *p != ''; ++p)
  782. ;
  783. for (--p; isspace((int)*p); --p)
  784. ;
  785. ++p;
  786. if (p == value) {
  787. illegal: __db_err(dbenv, "mis-formatted name-value pair: %s", s);
  788. return (EINVAL);
  789. }
  790. *p = '';
  791. if (!strcasecmp(name, "set_cachesize")) {
  792. if (sscanf(value, "%lu %lu %lu %c", &v1, &v2, &v3, &v4) != 3)
  793. goto badarg;
  794. __DB_OVFL(v1, UINT32_T_MAX);
  795. __DB_OVFL(v2, UINT32_T_MAX);
  796. __DB_OVFL(v3, 10000);
  797. return (dbenv->set_cachesize(
  798.     dbenv, (u_int32_t)v1, (u_int32_t)v2, (int)v3));
  799. }
  800. if (!strcasecmp(name, "set_data_dir") ||
  801.     !strcasecmp(name, "db_data_dir")) /* Compatibility. */
  802. return (dbenv->set_data_dir(dbenv, value));
  803. if (!strcasecmp(name, "set_flags")) {
  804. if (sscanf(value, "%40s %c", arg, &v4) != 1)
  805. goto badarg;
  806. if (!strcasecmp(value, "db_cdb_alldb"))
  807. return (dbenv->set_flags(dbenv, DB_CDB_ALLDB, 1));
  808. if (!strcasecmp(value, "db_direct_db"))
  809. return (dbenv->set_flags(dbenv, DB_DIRECT_DB, 1));
  810. if (!strcasecmp(value, "db_direct_log"))
  811. return (dbenv->set_flags(dbenv, DB_DIRECT_LOG, 1));
  812. if (!strcasecmp(value, "db_nolocking"))
  813. return (dbenv->set_flags(dbenv, DB_NOLOCKING, 1));
  814. if (!strcasecmp(value, "db_nommap"))
  815. return (dbenv->set_flags(dbenv, DB_NOMMAP, 1));
  816. if (!strcasecmp(value, "db_overwrite"))
  817. return (dbenv->set_flags(dbenv, DB_OVERWRITE, 1));
  818. if (!strcasecmp(value, "db_nopanic"))
  819. return (dbenv->set_flags(dbenv, DB_NOPANIC, 1));
  820. if (!strcasecmp(value, "db_region_init"))
  821. return (dbenv->set_flags(dbenv, DB_REGION_INIT, 1));
  822. if (!strcasecmp(value, "db_txn_nosync"))
  823. return (dbenv->set_flags(dbenv, DB_TXN_NOSYNC, 1));
  824. if (!strcasecmp(value, "db_txn_write_nosync"))
  825. return (
  826.     dbenv->set_flags(dbenv, DB_TXN_WRITE_NOSYNC, 1));
  827. if (!strcasecmp(value, "db_yieldcpu"))
  828. return (dbenv->set_flags(dbenv, DB_YIELDCPU, 1));
  829. goto badarg;
  830. }
  831. if (!strcasecmp(name, "set_lg_bsize")) {
  832. if (sscanf(value, "%lu %c", &v1, &v4) != 1)
  833. goto badarg;
  834. __DB_OVFL(v1, UINT32_T_MAX);
  835. return (dbenv->set_lg_bsize(dbenv, (u_int32_t)v1));
  836. }
  837. if (!strcasecmp(name, "set_lg_max")) {
  838. if (sscanf(value, "%lu %c", &v1, &v4) != 1)
  839. goto badarg;
  840. __DB_OVFL(v1, UINT32_T_MAX);
  841. return (dbenv->set_lg_max(dbenv, (u_int32_t)v1));
  842. }
  843. if (!strcasecmp(name, "set_lg_regionmax")) {
  844. if (sscanf(value, "%lu %c", &v1, &v4) != 1)
  845. goto badarg;
  846. __DB_OVFL(v1, UINT32_T_MAX);
  847. return (dbenv->set_lg_regionmax(dbenv, (u_int32_t)v1));
  848. }
  849. if (!strcasecmp(name, "set_lg_dir") ||
  850.     !strcasecmp(name, "db_log_dir")) /* Compatibility. */
  851. return (dbenv->set_lg_dir(dbenv, value));
  852. if (!strcasecmp(name, "set_lk_detect")) {
  853. if (sscanf(value, "%40s %c", arg, &v4) != 1)
  854. goto badarg;
  855. if (!strcasecmp(value, "db_lock_default"))
  856. flags = DB_LOCK_DEFAULT;
  857. else if (!strcasecmp(value, "db_lock_expire"))
  858. flags = DB_LOCK_EXPIRE;
  859. else if (!strcasecmp(value, "db_lock_maxlocks"))
  860. flags = DB_LOCK_MAXLOCKS;
  861. else if (!strcasecmp(value, "db_lock_minlocks"))
  862. flags = DB_LOCK_MINLOCKS;
  863. else if (!strcasecmp(value, "db_lock_minwrite"))
  864. flags = DB_LOCK_MINWRITE;
  865. else if (!strcasecmp(value, "db_lock_oldest"))
  866. flags = DB_LOCK_OLDEST;
  867. else if (!strcasecmp(value, "db_lock_random"))
  868. flags = DB_LOCK_RANDOM;
  869. else if (!strcasecmp(value, "db_lock_youngest"))
  870. flags = DB_LOCK_YOUNGEST;
  871. else
  872. goto badarg;
  873. return (dbenv->set_lk_detect(dbenv, flags));
  874. }
  875. if (!strcasecmp(name, "set_lk_max")) {
  876. if (sscanf(value, "%lu %c", &v1, &v4) != 1)
  877. goto badarg;
  878. __DB_OVFL(v1, UINT32_T_MAX);
  879. return (dbenv->set_lk_max(dbenv, (u_int32_t)v1));
  880. }
  881. if (!strcasecmp(name, "set_lk_max_locks")) {
  882. if (sscanf(value, "%lu %c", &v1, &v4) != 1)
  883. goto badarg;
  884. __DB_OVFL(v1, UINT32_T_MAX);
  885. return (dbenv->set_lk_max_locks(dbenv, (u_int32_t)v1));
  886. }
  887. if (!strcasecmp(name, "set_lk_max_lockers")) {
  888. if (sscanf(value, "%lu %c", &v1, &v4) != 1)
  889. goto badarg;
  890. __DB_OVFL(v1, UINT32_T_MAX);
  891. return (dbenv->set_lk_max_lockers(dbenv, (u_int32_t)v1));
  892. }
  893. if (!strcasecmp(name, "set_lk_max_objects")) {
  894. if (sscanf(value, "%lu %c", &v1, &v4) != 1)
  895. goto badarg;
  896. __DB_OVFL(v1, UINT32_T_MAX);
  897. return (dbenv->set_lk_max_objects(dbenv, (u_int32_t)v1));
  898. }
  899. if (!strcasecmp(name, "set_lock_timeout")) {
  900. if (sscanf(value, "%lu %c", &v1, &v4) != 1)
  901. goto badarg;
  902. __DB_OVFL(v1, UINT32_T_MAX);
  903. return (dbenv->set_timeout(
  904.     dbenv, (u_int32_t)v1, DB_SET_LOCK_TIMEOUT));
  905. }
  906. if (!strcasecmp(name, "set_mp_mmapsize")) {
  907. if (sscanf(value, "%lu %c", &v1, &v4) != 1)
  908. goto badarg;
  909. __DB_OVFL(v1, UINT32_T_MAX);
  910. return (dbenv->set_mp_mmapsize(dbenv, (u_int32_t)v1));
  911. }
  912. if (!strcasecmp(name, "set_region_init")) {
  913. if (sscanf(value, "%lu %c", &v1, &v4) != 1 || v1 != 1)
  914. goto badarg;
  915. return (dbenv->set_flags(
  916.     dbenv, DB_REGION_INIT, v1 == 0 ? 0 : 1));
  917. }
  918. if (!strcasecmp(name, "set_shm_key")) {
  919. if (sscanf(value, "%lu %c", &v1, &v4) != 1)
  920. goto badarg;
  921. return (dbenv->set_shm_key(dbenv, (long)v1));
  922. }
  923. if (!strcasecmp(name, "set_tas_spins")) {
  924. if (sscanf(value, "%lu %c", &v1, &v4) != 1)
  925. goto badarg;
  926. __DB_OVFL(v1, UINT32_T_MAX);
  927. return (dbenv->set_tas_spins(dbenv, (u_int32_t)v1));
  928. }
  929. if (!strcasecmp(name, "set_tmp_dir") ||
  930.     !strcasecmp(name, "db_tmp_dir")) /* Compatibility.*/
  931. return (dbenv->set_tmp_dir(dbenv, value));
  932. if (!strcasecmp(name, "set_tx_max")) {
  933. if (sscanf(value, "%lu %c", &v1, &v4) != 1)
  934. goto badarg;
  935. __DB_OVFL(v1, UINT32_T_MAX);
  936. return (dbenv->set_tx_max(dbenv, (u_int32_t)v1));
  937. }
  938. if (!strcasecmp(name, "set_txn_timeout")) {
  939. if (sscanf(value, "%lu %c", &v1, &v4) != 1)
  940. goto badarg;
  941. __DB_OVFL(v1, UINT32_T_MAX);
  942. return (dbenv->set_timeout(
  943.     dbenv, (u_int32_t)v1, DB_SET_TXN_TIMEOUT));
  944. }
  945. if (!strcasecmp(name, "set_verbose")) {
  946. if (sscanf(value, "%40s %c", arg, &v4) != 1)
  947. goto badarg;
  948. if (!strcasecmp(value, "db_verb_chkpoint"))
  949. flags = DB_VERB_CHKPOINT;
  950. else if (!strcasecmp(value, "db_verb_deadlock"))
  951. flags = DB_VERB_DEADLOCK;
  952. else if (!strcasecmp(value, "db_verb_recovery"))
  953. flags = DB_VERB_RECOVERY;
  954. else if (!strcasecmp(value, "db_verb_waitsfor"))
  955. flags = DB_VERB_WAITSFOR;
  956. else
  957. goto badarg;
  958. return (dbenv->set_verbose(dbenv, flags, 1));
  959. }
  960. __db_err(dbenv, "unrecognized name-value pair: %s", s);
  961. return (EINVAL);
  962. badarg: __db_err(dbenv, "incorrect arguments for name-value pair: %s", s);
  963. return (EINVAL);
  964. toobig: __db_err(dbenv,
  965.     "%s: %lu larger than maximum value %lu", s, __v, __max);
  966. return (EINVAL);
  967. }
  968. /*
  969.  * __db_tmp_open --
  970.  * Create a temporary file.
  971.  */
  972. static int
  973. __db_tmp_open(dbenv, tmp_oflags, path, fhp)
  974. DB_ENV *dbenv;
  975. u_int32_t tmp_oflags;
  976. char *path;
  977. DB_FH *fhp;
  978. {
  979. u_int32_t id;
  980. int mode, isdir, ret;
  981. const char *p;
  982. char *trv;
  983. /*
  984.  * Check the target directory; if you have six X's and it doesn't
  985.  * exist, this runs for a *very* long time.
  986.  */
  987. if ((ret = __os_exists(path, &isdir)) != 0) {
  988. __db_err(dbenv, "%s: %s", path, db_strerror(ret));
  989. return (ret);
  990. }
  991. if (!isdir) {
  992. __db_err(dbenv, "%s: %s", path, db_strerror(EINVAL));
  993. return (EINVAL);
  994. }
  995. /* Build the path. */
  996. for (trv = path; *trv != ''; ++trv)
  997. ;
  998. *trv = PATH_SEPARATOR[0];
  999. for (p = DB_TRAIL; (*++trv = *p) != ''; ++p)
  1000. ;
  1001. /* Replace the X's with the process ID. */
  1002. for (__os_id(&id); *--trv == 'X'; id /= 10)
  1003. switch (id % 10) {
  1004. case 0: *trv = '0'; break;
  1005. case 1: *trv = '1'; break;
  1006. case 2: *trv = '2'; break;
  1007. case 3: *trv = '3'; break;
  1008. case 4: *trv = '4'; break;
  1009. case 5: *trv = '5'; break;
  1010. case 6: *trv = '6'; break;
  1011. case 7: *trv = '7'; break;
  1012. case 8: *trv = '8'; break;
  1013. case 9: *trv = '9'; break;
  1014. }
  1015. ++trv;
  1016. /* Set up open flags and mode. */
  1017. mode = __db_omode("rw----");
  1018. /* Loop, trying to open a file. */
  1019. for (;;) {
  1020. if ((ret = __os_open(dbenv, path,
  1021.     tmp_oflags | DB_OSO_CREATE | DB_OSO_EXCL | DB_OSO_TEMP,
  1022.     mode, fhp)) == 0)
  1023. return (0);
  1024. /*
  1025.  * !!!:
  1026.  * If we don't get an EEXIST error, then there's something
  1027.  * seriously wrong.  Unfortunately, if the implementation
  1028.  * doesn't return EEXIST for O_CREAT and O_EXCL regardless
  1029.  * of other possible errors, we've lost.
  1030.  */
  1031. if (ret != EEXIST) {
  1032. __db_err(dbenv,
  1033.     "tmp_open: %s: %s", path, db_strerror(ret));
  1034. return (ret);
  1035. }
  1036. /*
  1037.  * Tricky little algorithm for backward compatibility.
  1038.  * Assumes sequential ordering of lower-case characters.
  1039.  */
  1040. for (;;) {
  1041. if (*trv == '')
  1042. return (EINVAL);
  1043. if (*trv == 'z')
  1044. *trv++ = 'a';
  1045. else {
  1046. if (isdigit((int)*trv))
  1047. *trv = 'a';
  1048. else
  1049. ++*trv;
  1050. break;
  1051. }
  1052. }
  1053. }
  1054. /* NOTREACHED */
  1055. }