env_open.c
上传用户:tsgydb
上传日期:2007-04-14
资源大小:10674k
文件大小:27k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /*-
  2.  * See the file LICENSE for redistribution information.
  3.  *
  4.  * Copyright (c) 1996, 1997, 1998, 1999, 2000
  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.34 2000/12/21 19:20:00 bostic 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 "db_page.h"
  20. #include "db_shash.h"
  21. #include "btree.h"
  22. #include "hash.h"
  23. #include "qam.h"
  24. #include "lock.h"
  25. #include "log.h"
  26. #include "mp.h"
  27. #include "txn.h"
  28. #include "clib_ext.h"
  29. static int __dbenv_config __P((DB_ENV *, const char *, u_int32_t));
  30. static int __dbenv_refresh __P((DB_ENV *));
  31. static int __db_home __P((DB_ENV *, const char *, u_int32_t));
  32. static int __db_parse __P((DB_ENV *, char *));
  33. static int __db_tmp_open __P((DB_ENV *, u_int32_t, char *, DB_FH *));
  34. /*
  35.  * db_version --
  36.  * Return version information.
  37.  */
  38. char *
  39. db_version(majverp, minverp, patchp)
  40. int *majverp, *minverp, *patchp;
  41. {
  42. if (majverp != NULL)
  43. *majverp = DB_VERSION_MAJOR;
  44. if (minverp != NULL)
  45. *minverp = DB_VERSION_MINOR;
  46. if (patchp != NULL)
  47. *patchp = DB_VERSION_PATCH;
  48. return ((char *)DB_VERSION_STRING);
  49. }
  50. /*
  51.  * __dbenv_open --
  52.  * Initialize an environment.
  53.  *
  54.  * PUBLIC: int __dbenv_open __P((DB_ENV *, const char *, u_int32_t, int));
  55.  */
  56. int
  57. __dbenv_open(dbenv, db_home, flags, mode)
  58. DB_ENV *dbenv;
  59. const char *db_home;
  60. u_int32_t flags;
  61. int mode;
  62. {
  63. DB_ENV *rm_dbenv;
  64. int ret;
  65. u_int32_t init_flags;
  66. #undef OKFLAGS
  67. #define OKFLAGS
  68. DB_CREATE | DB_INIT_CDB | DB_INIT_LOCK | DB_INIT_LOG |
  69. DB_INIT_MPOOL | DB_INIT_TXN | DB_JOINENV | DB_LOCKDOWN |
  70. DB_PRIVATE | DB_RECOVER | DB_RECOVER_FATAL | DB_SYSTEM_MEM |
  71. DB_THREAD | DB_USE_ENVIRON | DB_USE_ENVIRON_ROOT
  72. #undef OKFLAGS_CDB
  73. #define OKFLAGS_CDB
  74. DB_CREATE | DB_INIT_CDB | DB_INIT_MPOOL | DB_LOCKDOWN |
  75. DB_PRIVATE | DB_SYSTEM_MEM | DB_THREAD |
  76. DB_USE_ENVIRON | DB_USE_ENVIRON_ROOT
  77. /*
  78.  * Flags saved in the init_flags field of the environment, representing
  79.  * flags to DBENV->set_flags and DBENV->open that need to be set.
  80.  */
  81. #define DB_INITENV_CDB 0x0001 /* DB_INIT_CDB */
  82. #define DB_INITENV_CDB_ALLDB 0x0002 /* DB_INIT_CDB_ALLDB */
  83. #define DB_INITENV_LOCK 0x0004 /* DB_INIT_LOCK */
  84. #define DB_INITENV_LOG 0x0008 /* DB_INIT_LOG */
  85. #define DB_INITENV_MPOOL 0x0010 /* DB_INIT_MPOOL */
  86. #define DB_INITENV_TXN 0x0020 /* DB_INIT_TXN */
  87. if ((ret = __db_fchk(dbenv, "DBENV->open", flags, OKFLAGS)) != 0)
  88. return (ret);
  89. if (LF_ISSET(DB_INIT_CDB) &&
  90.     (ret = __db_fchk(dbenv, "DBENV->open", flags, OKFLAGS_CDB)) != 0)
  91. return (ret);
  92. if ((ret = __db_fcchk(dbenv,
  93.     "DBENV->open", flags, DB_PRIVATE, DB_SYSTEM_MEM)) != 0)
  94. return (ret);
  95. if ((ret = __db_fcchk(dbenv, "DBENV->open", flags, DB_JOINENV,
  96.     DB_CREATE | DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_MPOOL |
  97.     DB_INIT_TXN | DB_PRIVATE)) != 0)
  98. return (ret);
  99. /*
  100.  * If we're doing recovery, destroy the environment so that we create
  101.  * all the regions from scratch.  I'd like to reuse already created
  102.  * regions, but that's hard.  We would have to create the environment
  103.  * region from scratch, at least, as we have no way of knowing if its
  104.  * linked lists are corrupted.
  105.  *
  106.  * I suppose we could set flags while modifying those links, but that
  107.  * is going to be difficult to get right.  The major concern I have
  108.  * is if the application stomps the environment with a rogue pointer.
  109.  * We have no way of detecting that, and we could be forced into a
  110.  * situation where we start up and then crash, repeatedly.
  111.  *
  112.  * Note that we do not check any flags like DB_PRIVATE before calling
  113.  * remove.  We don't care if the current environment was private or
  114.  * not, we just want to nail any files that are left-over for whatever
  115.  * reason, from whatever session.
  116.  */
  117. if (LF_ISSET(DB_RECOVER | DB_RECOVER_FATAL)) {
  118. if ((ret = db_env_create(&rm_dbenv, 0)) != 0)
  119. return (ret);
  120. if ((ret = dbenv->remove(rm_dbenv, db_home, DB_FORCE)) != 0)
  121. return (ret);
  122. }
  123. /* Initialize the DB_ENV structure. */
  124. if ((ret = __dbenv_config(dbenv, db_home, flags)) != 0)
  125. goto err;
  126. /* Convert the DBENV->open flags to internal flags. */
  127. if (LF_ISSET(DB_CREATE))
  128. F_SET(dbenv, DB_ENV_CREATE);
  129. if (LF_ISSET(DB_LOCKDOWN))
  130. F_SET(dbenv, DB_ENV_LOCKDOWN);
  131. if (LF_ISSET(DB_PRIVATE))
  132. F_SET(dbenv, DB_ENV_PRIVATE);
  133. if (LF_ISSET(DB_SYSTEM_MEM))
  134. F_SET(dbenv, DB_ENV_SYSTEM_MEM);
  135. if (LF_ISSET(DB_THREAD))
  136. F_SET(dbenv, DB_ENV_THREAD);
  137. /* Default permissions are read-write for both owner and group. */
  138. dbenv->db_mode = mode == 0 ? __db_omode("rwrw--") : mode;
  139. /*
  140.  * Create/join the environment.  We pass in the flags that
  141.  * will be of interest to an environment joining later;  if
  142.  * we're not the ones to do the create, we
  143.  * pull out whatever has been stored, if we don't do a create.
  144.  */
  145. init_flags = 0;
  146. init_flags |= (LF_ISSET(DB_INIT_CDB) ? DB_INITENV_CDB : 0);
  147. init_flags |= (LF_ISSET(DB_INIT_LOCK) ? DB_INITENV_LOCK : 0);
  148. init_flags |= (LF_ISSET(DB_INIT_LOG) ? DB_INITENV_LOG : 0);
  149. init_flags |= (LF_ISSET(DB_INIT_MPOOL) ? DB_INITENV_MPOOL : 0);
  150. init_flags |= (LF_ISSET(DB_INIT_TXN) ? DB_INITENV_TXN : 0);
  151. init_flags |=
  152.     (F_ISSET(dbenv, DB_ENV_CDB_ALLDB) ? DB_INITENV_CDB_ALLDB : 0);
  153. if ((ret = __db_e_attach(dbenv, &init_flags)) != 0)
  154. goto err;
  155. /*
  156.  * __db_e_attach will return the saved init_flags field, which
  157.  * contains the DB_INIT_* flags used when we were created.
  158.  */
  159. if (LF_ISSET(DB_JOINENV)) {
  160. LF_CLR(DB_JOINENV);
  161. LF_SET((init_flags & DB_INITENV_CDB) ? DB_INIT_CDB : 0);
  162. LF_SET((init_flags & DB_INITENV_LOCK) ? DB_INIT_LOCK : 0);
  163. LF_SET((init_flags & DB_INITENV_LOG) ? DB_INIT_LOG : 0);
  164. LF_SET((init_flags & DB_INITENV_MPOOL) ? DB_INIT_MPOOL : 0);
  165. LF_SET((init_flags & DB_INITENV_TXN) ? DB_INIT_TXN : 0);
  166. if (LF_ISSET(DB_INITENV_CDB_ALLDB) &&
  167.     (ret = dbenv->set_flags(dbenv, DB_CDB_ALLDB, 1)) != 0)
  168. goto err;
  169. }
  170. /* Initialize for CDB product. */
  171. if (LF_ISSET(DB_INIT_CDB)) {
  172. LF_SET(DB_INIT_LOCK);
  173. F_SET(dbenv, DB_ENV_CDB);
  174. }
  175. /* Initialize the DB list, and its mutex if appropriate. */
  176. LIST_INIT(&dbenv->dblist);
  177. if (F_ISSET(dbenv, DB_ENV_THREAD)) {
  178. if ((ret = __db_mutex_alloc(dbenv,
  179.     dbenv->reginfo, (MUTEX **)&dbenv->dblist_mutexp)) != 0)
  180. return (ret);
  181. if ((ret = __db_mutex_init(dbenv,
  182.     dbenv->dblist_mutexp, 0, MUTEX_THREAD)) != 0) {
  183. __db_mutex_free(dbenv, dbenv->reginfo,
  184.     dbenv->dblist_mutexp);
  185. return (ret);
  186. }
  187. }
  188. /*
  189.  * Initialize the subsystems.  Transactions imply logging but do not
  190.  * imply locking.  While almost all applications want both locking
  191.  * and logging, it would not be unreasonable for a single threaded
  192.  * process to want transactions for atomicity guarantees, but not
  193.  * necessarily need concurrency.
  194.  */
  195. if (LF_ISSET(DB_INIT_MPOOL))
  196. if ((ret = __memp_open(dbenv)) != 0)
  197. goto err;
  198. if (LF_ISSET(DB_INIT_LOG | DB_INIT_TXN))
  199. if ((ret = __log_open(dbenv)) != 0)
  200. goto err;
  201. if (LF_ISSET(DB_INIT_LOCK))
  202. if ((ret = __lock_open(dbenv)) != 0)
  203. goto err;
  204. if (LF_ISSET(DB_INIT_TXN)) {
  205. if ((ret = __txn_open(dbenv)) != 0)
  206. goto err;
  207. /*
  208.  * If the application is running with transactions, initialize
  209.  * the function tables.
  210.  */
  211. if ((ret = __bam_init_recover(dbenv)) != 0)
  212. goto err;
  213. if ((ret = __crdel_init_recover(dbenv)) != 0)
  214. goto err;
  215. if ((ret = __db_init_recover(dbenv)) != 0)
  216. goto err;
  217. if ((ret = __ham_init_recover(dbenv)) != 0)
  218. goto err;
  219. if ((ret = __log_init_recover(dbenv)) != 0)
  220. goto err;
  221. if ((ret = __qam_init_recover(dbenv)) != 0)
  222. goto err;
  223. if ((ret = __txn_init_recover(dbenv)) != 0)
  224. goto err;
  225. /*
  226.  * If the application specified their own recovery
  227.  * initialization function, call it.
  228.  */
  229. if (dbenv->db_recovery_init != NULL &&
  230.     (ret = dbenv->db_recovery_init(dbenv)) != 0)
  231. goto err;
  232. /* Perform recovery for any previous run. */
  233. if (LF_ISSET(DB_RECOVER | DB_RECOVER_FATAL) &&
  234.     (ret = __db_apprec(dbenv,
  235.     LF_ISSET(DB_RECOVER | DB_RECOVER_FATAL))) != 0)
  236. goto err;
  237. }
  238. return (0);
  239. err: (void)__dbenv_refresh(dbenv);
  240. return (ret);
  241. }
  242. /*
  243.  * __dbenv_remove --
  244.  * Discard an environment.
  245.  *
  246.  * PUBLIC: int __dbenv_remove __P((DB_ENV *, const char *, u_int32_t));
  247.  */
  248. int
  249. __dbenv_remove(dbenv, db_home, flags)
  250. DB_ENV *dbenv;
  251. const char *db_home;
  252. u_int32_t flags;
  253. {
  254. int ret, t_ret;
  255. #undef OKFLAGS
  256. #define OKFLAGS
  257. DB_FORCE | DB_USE_ENVIRON | DB_USE_ENVIRON_ROOT
  258. /* Validate arguments. */
  259. if ((ret = __db_fchk(dbenv, "DBENV->remove", flags, OKFLAGS)) != 0)
  260. goto err;
  261. /*
  262.  * A hard-to-debug error is calling DBENV->remove after open.  That's
  263.  * not legal.  You have to close the original, already opened handle
  264.  * and then allocate a new DBENV handle to use for DBENV->remove.
  265.  */
  266. if (F_ISSET(dbenv, DB_ENV_OPEN_CALLED)) {
  267. __db_err(dbenv,
  268.     "DBENV handle opened, not usable for remove method.");
  269. return (EINVAL);
  270. }
  271. /* Initialize the DB_ENV structure. */
  272. if ((ret = __dbenv_config(dbenv, db_home, flags)) != 0)
  273. goto err;
  274. /* Remove the environment. */
  275. ret = __db_e_remove(dbenv, LF_ISSET(DB_FORCE) ? 1 : 0);
  276. /* Discard any resources we've acquired. */
  277. err: if ((t_ret = __dbenv_refresh(dbenv)) != 0 && ret == 0)
  278. ret = t_ret;
  279. memset(dbenv, CLEAR_BYTE, sizeof(DB_ENV));
  280. __os_free(dbenv, sizeof(DB_ENV));
  281. return (ret);
  282. }
  283. /*
  284.  * __dbenv_config --
  285.  * Initialize the DB_ENV structure.
  286.  */
  287. static int
  288. __dbenv_config(dbenv, db_home, flags)
  289. DB_ENV *dbenv;
  290. const char *db_home;
  291. u_int32_t flags;
  292. {
  293. FILE *fp;
  294. int ret;
  295. char *lp, buf[MAXPATHLEN * 2];
  296. /* Set the database home. */
  297. if ((ret = __db_home(dbenv, db_home, flags)) != 0)
  298. return (ret);
  299. /*
  300.  * Parse the config file.
  301.  *
  302.  * !!!
  303.  * Don't use sprintf(3)/snprintf(3) -- the former is dangerous, and
  304.  * the latter isn't standard, and we're manipulating strings handed
  305.  * us by the application.
  306.  */
  307. if (dbenv->db_home != NULL) {
  308. #define CONFIG_NAME "/DB_CONFIG"
  309. if (strlen(dbenv->db_home) +
  310.     strlen(CONFIG_NAME) + 1 > sizeof(buf)) {
  311. ret = ENAMETOOLONG;
  312. return (ret);
  313. }
  314. (void)strcpy(buf, dbenv->db_home);
  315. (void)strcat(buf, CONFIG_NAME);
  316. if ((fp = fopen(buf, "r")) != NULL) {
  317. while (fgets(buf, sizeof(buf), fp) != NULL) {
  318. if ((lp = strchr(buf, 'n')) == NULL) {
  319. __db_err(dbenv,
  320.     "%s: line too long", CONFIG_NAME);
  321. (void)fclose(fp);
  322. ret = EINVAL;
  323. return (ret);
  324. }
  325. *lp = '';
  326. if (buf[0] == '' ||
  327.     buf[0] == '#' || isspace((int)buf[0]))
  328. continue;
  329. if ((ret = __db_parse(dbenv, buf)) != 0) {
  330. (void)fclose(fp);
  331. return (ret);
  332. }
  333. }
  334. (void)fclose(fp);
  335. }
  336. }
  337. /* Set up the tmp directory path. */
  338. if (dbenv->db_tmp_dir == NULL && (ret = __os_tmpdir(dbenv, flags)) != 0)
  339. return (ret);
  340. /*
  341.  * The locking file descriptor is rarely on.  Set the fd to -1, not
  342.  * because it's ever tested, but to make sure we catch mistakes.
  343.  */
  344. if ((ret =
  345.     __os_calloc(dbenv,
  346. 1, sizeof(*dbenv->lockfhp), &dbenv->lockfhp)) != 0)
  347. return (ret);
  348. dbenv->lockfhp->fd = -1;
  349. /*
  350.  * Flag that the DB_ENV structure has been initialized.  Note, this
  351.  * must be set before calling into the subsystems as it's used during
  352.  * file naming.
  353.  */
  354. F_SET(dbenv, DB_ENV_OPEN_CALLED);
  355. return (0);
  356. }
  357. /*
  358.  * __dbenv_close --
  359.  * DB_ENV destructor.
  360.  *
  361.  * PUBLIC: int __dbenv_close __P((DB_ENV *, u_int32_t));
  362.  */
  363. int
  364. __dbenv_close(dbenv, flags)
  365. DB_ENV *dbenv;
  366. u_int32_t flags;
  367. {
  368. int ret;
  369. COMPQUIET(flags, 0);
  370. PANIC_CHECK(dbenv);
  371. ret = __dbenv_refresh(dbenv);
  372. /* Discard the structure if we allocated it. */
  373. if (!F_ISSET(dbenv, DB_ENV_USER_ALLOC)) {
  374. memset(dbenv, CLEAR_BYTE, sizeof(DB_ENV));
  375. __os_free(dbenv, sizeof(DB_ENV));
  376. }
  377. return (ret);
  378. }
  379. /*
  380.  * __dbenv_refresh --
  381.  * Refresh the DB_ENV structure, releasing any allocated resources.
  382.  */
  383. static int
  384. __dbenv_refresh(dbenv)
  385. DB_ENV *dbenv;
  386. {
  387. int ret, t_ret;
  388. char **p;
  389. ret = 0;
  390. /*
  391.  * Close subsystems, in the reverse order they were opened (txn
  392.  * must be first, it may want to discard locks and flush the log).
  393.  */
  394. if (TXN_ON(dbenv)) {
  395. if ((t_ret = __txn_close(dbenv)) != 0 && ret == 0)
  396. ret = t_ret;
  397. }
  398. if (LOCKING_ON(dbenv)) {
  399. if ((t_ret = __lock_close(dbenv)) != 0 && ret == 0)
  400. ret = t_ret;
  401. }
  402. __lock_dbenv_close(dbenv);
  403. if (LOGGING_ON(dbenv)) {
  404. if ((t_ret = __log_close(dbenv)) != 0 && ret == 0)
  405. ret = t_ret;
  406. }
  407. if (MPOOL_ON(dbenv)) {
  408. if ((t_ret = __memp_close(dbenv)) != 0 && ret == 0)
  409. ret = t_ret;
  410. }
  411. /* Discard DB list and its mutex. */
  412. LIST_INIT(&dbenv->dblist);
  413. if (dbenv->dblist_mutexp != NULL)
  414. __db_mutex_free(dbenv, dbenv->reginfo, dbenv->dblist_mutexp);
  415. /* Detach from the region. */
  416. if (dbenv->reginfo != NULL) {
  417. if ((t_ret = __db_e_detach(dbenv, 0)) != 0 && ret == 0)
  418. ret = t_ret;
  419. /*
  420.  * !!!
  421.  * Don't free dbenv->reginfo or set the reference to NULL,
  422.  * that was done by __db_e_detach().
  423.  */
  424. }
  425. /* Clean up the structure. */
  426. dbenv->db_panic = 0;
  427. if (dbenv->db_home != NULL) {
  428. __os_freestr(dbenv->db_home);
  429. dbenv->db_home = NULL;
  430. }
  431. if (dbenv->db_log_dir != NULL) {
  432. __os_freestr(dbenv->db_log_dir);
  433. dbenv->db_log_dir = NULL;
  434. }
  435. if (dbenv->db_tmp_dir != NULL) {
  436. __os_freestr(dbenv->db_tmp_dir);
  437. dbenv->db_tmp_dir = NULL;
  438. }
  439. if (dbenv->db_data_dir != NULL) {
  440. for (p = dbenv->db_data_dir; *p != NULL; ++p)
  441. __os_freestr(*p);
  442. __os_free(dbenv->db_data_dir,
  443.     dbenv->data_cnt * sizeof(char **));
  444. dbenv->db_data_dir = NULL;
  445. }
  446. dbenv->data_cnt = dbenv->data_next = 0;
  447. dbenv->db_mode = 0;
  448. if (dbenv->lockfhp != NULL) {
  449. __os_free(dbenv->lockfhp, sizeof(*dbenv->lockfhp));
  450. dbenv->lockfhp = NULL;
  451. }
  452. if (dbenv->dtab != NULL) {
  453. __os_free(dbenv->dtab,
  454.     dbenv->dtab_size * sizeof(dbenv->dtab[0]));
  455. dbenv->dtab = NULL;
  456. dbenv->dtab_size = 0;
  457. }
  458. dbenv->mp_mmapsize = 0;
  459. dbenv->links.tqe_next = NULL;
  460. dbenv->links.tqe_prev = NULL;
  461. dbenv->xa_rmid = 0;
  462. dbenv->xa_txn = 0;
  463. F_CLR(dbenv, ~(DB_ENV_STANDALONE | DB_ENV_USER_ALLOC));
  464. return (ret);
  465. }
  466. #define DB_ADDSTR(add) {
  467. if ((add) != NULL) {
  468. /* If leading slash, start over. */
  469. if (__os_abspath(add)) {
  470. p = str;
  471. slash = 0;
  472. }
  473. /* Append to the current string. */
  474. len = strlen(add);
  475. if (slash)
  476. *p++ = PATH_SEPARATOR[0];
  477. memcpy(p, add, len);
  478. p += len;
  479. slash = strchr(PATH_SEPARATOR, p[-1]) == NULL;
  480. }
  481. }
  482. /*
  483.  * __db_appname --
  484.  * Given an optional DB environment, directory and file name and type
  485.  * of call, build a path based on the DBENV->open rules, and return
  486.  * it in allocated space.
  487.  *
  488.  * PUBLIC: int __db_appname __P((DB_ENV *, APPNAME,
  489.  * PUBLIC:    const char *, const char *, u_int32_t, DB_FH *, char **));
  490.  */
  491. int
  492. __db_appname(dbenv, appname, dir, file, tmp_oflags, fhp, namep)
  493. DB_ENV *dbenv;
  494. APPNAME appname;
  495. const char *dir, *file;
  496. u_int32_t tmp_oflags;
  497. DB_FH *fhp;
  498. char **namep;
  499. {
  500. DB_ENV etmp;
  501. size_t len, str_len;
  502. int data_entry, ret, slash, tmp_create, tmp_free;
  503. const char *a, *b, *c;
  504. char *p, *str;
  505. a = b = c = NULL;
  506. data_entry = -1;
  507. tmp_create = tmp_free = 0;
  508. /*
  509.  * We don't return a name when creating temporary files, just a
  510.  * file handle.  Default to an error now.
  511.  */
  512. if (fhp != NULL)
  513. F_CLR(fhp, DB_FH_VALID);
  514. if (namep != NULL)
  515. *namep = NULL;
  516. /*
  517.  * Absolute path names are never modified.  If the file is an absolute
  518.  * path, we're done.  If the directory is, simply append the file and
  519.  * return.
  520.  */
  521. if (file != NULL && __os_abspath(file))
  522. return (__os_strdup(dbenv, file, namep));
  523. if (dir != NULL && __os_abspath(dir)) {
  524. a = dir;
  525. goto done;
  526. }
  527. /*
  528.  * DB_ENV  DIR    APPNAME    RESULT
  529.  * -------------------------------------------
  530.  * null    null    none    <tmp>/file
  531.  * null    set    none    DIR/file
  532.  * set    null    none    DB_HOME/file
  533.  * set    set    none    DB_HOME/DIR/file
  534.  *
  535.  * DB_ENV  FILE    APPNAME    RESULT
  536.  * -------------------------------------------
  537.  * null    null    DB_APP_DATA    <tmp>/<create>
  538.  * null    set    DB_APP_DATA    ./file
  539.  * set    null    DB_APP_DATA    <tmp>/<create>
  540.  * set    set    DB_APP_DATA    DB_HOME/DB_DATA_DIR/file
  541.  *
  542.  * DB_ENV  DIR    APPNAME    RESULT
  543.  * -------------------------------------------
  544.  * null    null    DB_APP_LOG    <tmp>/file
  545.  * null    set    DB_APP_LOG    DIR/file
  546.  * set    null    DB_APP_LOG    DB_HOME/DB_LOG_DIR/file
  547.  * set    set    DB_APP_LOG    DB_HOME/DB_LOG_DIR/DIR/file
  548.  *
  549.  * DB_ENV    APPNAME    RESULT
  550.  * -------------------------------------------
  551.  * null    DB_APP_TMP*    <tmp>/<create>
  552.  * set    DB_APP_TMP*    DB_HOME/DB_TMP_DIR/<create>
  553.  */
  554. retry: switch (appname) {
  555. case DB_APP_NONE:
  556. if (dbenv == NULL || !F_ISSET(dbenv, DB_ENV_OPEN_CALLED)) {
  557. if (dir == NULL)
  558. goto tmp;
  559. a = dir;
  560. } else {
  561. a = dbenv->db_home;
  562. b = dir;
  563. }
  564. break;
  565. case DB_APP_DATA:
  566. if (dir != NULL) {
  567. __db_err(dbenv,
  568.     "DB_APP_DATA: illegal directory specification");
  569. return (EINVAL);
  570. }
  571. if (file == NULL) {
  572. tmp_create = 1;
  573. goto tmp;
  574. }
  575. if (dbenv != NULL && F_ISSET(dbenv, DB_ENV_OPEN_CALLED)) {
  576. a = dbenv->db_home;
  577. if (dbenv->db_data_dir != NULL &&
  578.     (b = dbenv->db_data_dir[++data_entry]) == NULL) {
  579. data_entry = -1;
  580. b = dbenv->db_data_dir[0];
  581. }
  582. }
  583. break;
  584. case DB_APP_LOG:
  585. if (dbenv == NULL || !F_ISSET(dbenv, DB_ENV_OPEN_CALLED)) {
  586. if (dir == NULL)
  587. goto tmp;
  588. a = dir;
  589. } else {
  590. a = dbenv->db_home;
  591. b = dbenv->db_log_dir;
  592. c = dir;
  593. }
  594. break;
  595. case DB_APP_TMP:
  596. if (dir != NULL || file != NULL) {
  597. __db_err(dbenv,
  598.     "DB_APP_TMP: illegal directory or file specification");
  599. return (EINVAL);
  600. }
  601. tmp_create = 1;
  602. if (dbenv == NULL || !F_ISSET(dbenv, DB_ENV_OPEN_CALLED))
  603. goto tmp;
  604. else {
  605. a = dbenv->db_home;
  606. b = dbenv->db_tmp_dir;
  607. }
  608. break;
  609. }
  610. /* Reference a file from the appropriate temporary directory. */
  611. if (0) {
  612. tmp: if (dbenv == NULL || !F_ISSET(dbenv, DB_ENV_OPEN_CALLED)) {
  613. memset(&etmp, 0, sizeof(etmp));
  614. if ((ret = __os_tmpdir(&etmp, DB_USE_ENVIRON)) != 0)
  615. return (ret);
  616. tmp_free = 1;
  617. a = etmp.db_tmp_dir;
  618. } else
  619. a = dbenv->db_tmp_dir;
  620. }
  621. done: len =
  622.     (a == NULL ? 0 : strlen(a) + 1) +
  623.     (b == NULL ? 0 : strlen(b) + 1) +
  624.     (c == NULL ? 0 : strlen(c) + 1) +
  625.     (file == NULL ? 0 : strlen(file) + 1);
  626. /*
  627.  * Allocate space to hold the current path information, as well as any
  628.  * temporary space that we're going to need to create a temporary file
  629.  * name.
  630.  */
  631. #define DB_TRAIL "BDBXXXXXX"
  632. str_len = len + sizeof(DB_TRAIL) + 10;
  633. if ((ret = __os_malloc(dbenv, str_len, NULL, &str)) != 0) {
  634. if (tmp_free)
  635. __os_freestr(etmp.db_tmp_dir);
  636. return (ret);
  637. }
  638. slash = 0;
  639. p = str;
  640. DB_ADDSTR(a);
  641. DB_ADDSTR(b);
  642. DB_ADDSTR(file);
  643. *p = '';
  644. /* Discard any space allocated to find the temp directory. */
  645. if (tmp_free) {
  646. __os_freestr(etmp.db_tmp_dir);
  647. tmp_free = 0;
  648. }
  649. /*
  650.  * If we're opening a data file, see if it exists.  If it does,
  651.  * return it, otherwise, try and find another one to open.
  652.  */
  653. if (data_entry != -1 && __os_exists(str, NULL) != 0) {
  654. __os_free(str, str_len);
  655. a = b = c = NULL;
  656. goto retry;
  657. }
  658. /* Create the file if so requested. */
  659. if (tmp_create &&
  660.     (ret = __db_tmp_open(dbenv, tmp_oflags, str, fhp)) != 0) {
  661. __os_free(str, str_len);
  662. return (ret);
  663. }
  664. if (namep == NULL)
  665. __os_free(str, str_len);
  666. else
  667. *namep = str;
  668. return (0);
  669. }
  670. /*
  671.  * __db_home --
  672.  * Find the database home.
  673.  */
  674. static int
  675. __db_home(dbenv, db_home, flags)
  676. DB_ENV *dbenv;
  677. const char *db_home;
  678. u_int32_t flags;
  679. {
  680. const char *p;
  681. /*
  682.  * Use db_home by default, this allows utilities to reasonably
  683.  * override the environment either explicitly or by using a -h
  684.  * option.  Otherwise, use the environment if it's permitted
  685.  * and initialized.
  686.  */
  687. if ((p = db_home) == NULL &&
  688.     (LF_ISSET(DB_USE_ENVIRON) ||
  689.     (LF_ISSET(DB_USE_ENVIRON_ROOT) && __os_isroot())) &&
  690.     (p = getenv("DB_HOME")) != NULL && p[0] == '') {
  691. __db_err(dbenv, "illegal DB_HOME environment variable");
  692. return (EINVAL);
  693. }
  694. return (p == NULL ? 0 : __os_strdup(dbenv, p, &dbenv->db_home));
  695. }
  696. /*
  697.  * __db_parse --
  698.  * Parse a single NAME VALUE pair.
  699.  */
  700. static int
  701. __db_parse(dbenv, s)
  702. DB_ENV *dbenv;
  703. char *s;
  704. {
  705. u_long v1, v2, v3;
  706. u_int32_t flags;
  707. char *name, *p, *value, v4;
  708. /*
  709.  * !!!
  710.  * The value of 40 is hard-coded into format arguments to sscanf
  711.  * below, it can't be changed here without changing it there, too.
  712.  */
  713. char arg[40];
  714. /*
  715.  * Name/value pairs are parsed as two white-space separated strings.
  716.  * Leading and trailing white-space is trimmed from the value, but
  717.  * it may contain embedded white-space.  Note: we use the isspace(3)
  718.  * macro because it's more portable, but that means that you can use
  719.  * characters like form-feed to separate the strings.
  720.  */
  721. name = s;
  722. for (p = name; *p != '' && !isspace((int)*p); ++p)
  723. ;
  724. if (*p == '' || p == name)
  725. goto illegal;
  726. *p = '';
  727. for (++p; isspace((int)*p); ++p)
  728. ;
  729. if (*p == '')
  730. goto illegal;
  731. value = p;
  732. for (++p; *p != ''; ++p)
  733. ;
  734. for (--p; isspace((int)*p); --p)
  735. ;
  736. ++p;
  737. if (p == value) {
  738. illegal: __db_err(dbenv, "mis-formatted name-value pair: %s", s);
  739. return (EINVAL);
  740. }
  741. *p = '';
  742. if (!strcasecmp(name, "set_cachesize")) {
  743. if (sscanf(value, "%lu %lu %lu %c", &v1, &v2, &v3, &v4) != 3)
  744. goto badarg;
  745. return (dbenv->set_cachesize(dbenv, v1, v2, v3));
  746. }
  747. if (!strcasecmp(name, "set_data_dir") ||
  748.     !strcasecmp(name, "db_data_dir")) /* Compatibility. */
  749. return (dbenv->set_data_dir(dbenv, value));
  750. if (!strcasecmp(name, "set_flags")) {
  751. if (sscanf(value, "%40s %c", arg, &v4) != 1)
  752. goto badarg;
  753. if (!strcasecmp(value, "db_cdb_alldb"))
  754. return (dbenv->set_flags(dbenv, DB_CDB_ALLDB, 1));
  755. if (!strcasecmp(value, "db_nommap"))
  756. return (dbenv->set_flags(dbenv, DB_NOMMAP, 1));
  757. if (!strcasecmp(value, "db_txn_nosync"))
  758. return (dbenv->set_flags(dbenv, DB_TXN_NOSYNC, 1));
  759. goto badarg;
  760. }
  761. if (!strcasecmp(name, "set_lg_bsize")) {
  762. if (sscanf(value, "%lu %c", &v1, &v4) != 1)
  763. goto badarg;
  764. return (dbenv->set_lg_bsize(dbenv, v1));
  765. }
  766. if (!strcasecmp(name, "set_lg_max")) {
  767. if (sscanf(value, "%lu %c", &v1, &v4) != 1)
  768. goto badarg;
  769. return (dbenv->set_lg_max(dbenv, v1));
  770. }
  771. if (!strcasecmp(name, "set_lg_dir") ||
  772.     !strcasecmp(name, "db_log_dir")) /* Compatibility. */
  773. return (dbenv->set_lg_dir(dbenv, value));
  774. if (!strcasecmp(name, "set_lk_detect")) {
  775. if (sscanf(value, "%40s %c", arg, &v4) != 1)
  776. goto badarg;
  777. if (!strcasecmp(value, "db_lock_default"))
  778. flags = DB_LOCK_DEFAULT;
  779. else if (!strcasecmp(value, "db_lock_oldest"))
  780. flags = DB_LOCK_OLDEST;
  781. else if (!strcasecmp(value, "db_lock_random"))
  782. flags = DB_LOCK_RANDOM;
  783. else if (!strcasecmp(value, "db_lock_youngest"))
  784. flags = DB_LOCK_YOUNGEST;
  785. else
  786. goto badarg;
  787. return (dbenv->set_lk_detect(dbenv, flags));
  788. }
  789. if (!strcasecmp(name, "set_lk_max")) {
  790. if (sscanf(value, "%lu %c", &v1, &v4) != 1)
  791. goto badarg;
  792. return (dbenv->set_lk_max(dbenv, v1));
  793. }
  794. if (!strcasecmp(name, "set_lk_max_locks")) {
  795. if (sscanf(value, "%lu %c", &v1, &v4) != 1)
  796. goto badarg;
  797. return (dbenv->set_lk_max_locks(dbenv, v1));
  798. }
  799. if (!strcasecmp(name, "set_lk_max_lockers")) {
  800. if (sscanf(value, "%lu %c", &v1, &v4) != 1)
  801. goto badarg;
  802. return (dbenv->set_lk_max_lockers(dbenv, v1));
  803. }
  804. if (!strcasecmp(name, "set_lk_max_objects")) {
  805. if (sscanf(value, "%lu %c", &v1, &v4) != 1)
  806. goto badarg;
  807. return (dbenv->set_lk_max_objects(dbenv, v1));
  808. }
  809. if (!strcasecmp(name, "set_mp_mmapsize")) {
  810. if (sscanf(value, "%lu %c", &v1, &v4) != 1)
  811. goto badarg;
  812. return (dbenv->set_mp_mmapsize(dbenv, v1));
  813. }
  814. if (!strcasecmp(name, "set_region_init")) {
  815. if (sscanf(value, "%lu %c", &v1, &v4) != 1 || v1 != 1)
  816. goto badarg;
  817. return (db_env_set_region_init(v1));
  818. }
  819. if (!strcasecmp(name, "set_shm_key")) {
  820. if (sscanf(value, "%lu %c", &v1, &v4) != 1)
  821. goto badarg;
  822. return (dbenv->set_shm_key(dbenv, (long)v1));
  823. }
  824. if (!strcasecmp(name, "set_tas_spins")) {
  825. if (sscanf(value, "%lu %c", &v1, &v4) != 1)
  826. goto badarg;
  827. return (db_env_set_tas_spins(v1));
  828. }
  829. if (!strcasecmp(name, "set_tmp_dir") ||
  830.     !strcasecmp(name, "db_tmp_dir")) /* Compatibility.*/
  831. return (dbenv->set_tmp_dir(dbenv, value));
  832. if (!strcasecmp(name, "set_tx_max")) {
  833. if (sscanf(value, "%lu %c", &v1, &v4) != 1)
  834. goto badarg;
  835. return (dbenv->set_tx_max(dbenv, v1));
  836. }
  837. if (!strcasecmp(name, "set_verbose")) {
  838. if (sscanf(value, "%40s %c", arg, &v4) != 1)
  839. goto badarg;
  840. if (!strcasecmp(value, "db_verb_chkpoint"))
  841. flags = DB_VERB_CHKPOINT;
  842. else if (!strcasecmp(value, "db_verb_deadlock"))
  843. flags = DB_VERB_DEADLOCK;
  844. else if (!strcasecmp(value, "db_verb_recovery"))
  845. flags = DB_VERB_RECOVERY;
  846. else if (!strcasecmp(value, "db_verb_waitsfor"))
  847. flags = DB_VERB_WAITSFOR;
  848. else
  849. goto badarg;
  850. return (dbenv->set_verbose(dbenv, flags, 1));
  851. }
  852. __db_err(dbenv, "unrecognized name-value pair: %s", s);
  853. return (EINVAL);
  854. badarg: __db_err(dbenv, "incorrect arguments for name-value pair: %s", s);
  855. return (EINVAL);
  856. }
  857. /*
  858.  * __db_tmp_open --
  859.  * Create a temporary file.
  860.  */
  861. static int
  862. __db_tmp_open(dbenv, tmp_oflags, path, fhp)
  863. DB_ENV *dbenv;
  864. u_int32_t tmp_oflags;
  865. char *path;
  866. DB_FH *fhp;
  867. {
  868. u_long pid;
  869. int mode, isdir, ret;
  870. const char *p;
  871. char *trv;
  872. /*
  873.  * Check the target directory; if you have six X's and it doesn't
  874.  * exist, this runs for a *very* long time.
  875.  */
  876. if ((ret = __os_exists(path, &isdir)) != 0) {
  877. __db_err(dbenv, "%s: %s", path, db_strerror(ret));
  878. return (ret);
  879. }
  880. if (!isdir) {
  881. __db_err(dbenv, "%s: %s", path, db_strerror(EINVAL));
  882. return (EINVAL);
  883. }
  884. /* Build the path. */
  885. for (trv = path; *trv != ''; ++trv)
  886. ;
  887. *trv = PATH_SEPARATOR[0];
  888. for (p = DB_TRAIL; (*++trv = *p) != ''; ++p)
  889. ;
  890. /*
  891.  * Replace the X's with the process ID.  Pid should be a pid_t,
  892.  * but we use unsigned long for portability.
  893.  */
  894. for (pid = getpid(); *--trv == 'X'; pid /= 10)
  895. switch (pid % 10) {
  896. case 0: *trv = '0'; break;
  897. case 1: *trv = '1'; break;
  898. case 2: *trv = '2'; break;
  899. case 3: *trv = '3'; break;
  900. case 4: *trv = '4'; break;
  901. case 5: *trv = '5'; break;
  902. case 6: *trv = '6'; break;
  903. case 7: *trv = '7'; break;
  904. case 8: *trv = '8'; break;
  905. case 9: *trv = '9'; break;
  906. }
  907. ++trv;
  908. /* Set up open flags and mode. */
  909. mode = __db_omode("rw----");
  910. /* Loop, trying to open a file. */
  911. for (;;) {
  912. if ((ret = __os_open(dbenv, path,
  913.     tmp_oflags | DB_OSO_CREATE | DB_OSO_EXCL, mode, fhp)) == 0)
  914. return (0);
  915. /*
  916.  * !!!:
  917.  * If we don't get an EEXIST error, then there's something
  918.  * seriously wrong.  Unfortunately, if the implementation
  919.  * doesn't return EEXIST for O_CREAT and O_EXCL regardless
  920.  * of other possible errors, we've lost.
  921.  */
  922. if (ret != EEXIST) {
  923. __db_err(dbenv,
  924.     "tmp_open: %s: %s", path, db_strerror(ret));
  925. return (ret);
  926. }
  927. /*
  928.  * Tricky little algorithm for backward compatibility.
  929.  * Assumes sequential ordering of lower-case characters.
  930.  */
  931. for (;;) {
  932. if (*trv == '')
  933. return (EINVAL);
  934. if (*trv == 'z')
  935. *trv++ = 'a';
  936. else {
  937. if (isdigit((int)*trv))
  938. *trv = 'a';
  939. else
  940. ++*trv;
  941. break;
  942. }
  943. }
  944. }
  945. /* NOTREACHED */
  946. }