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

MySQL数据库

开发平台:

Visual C++

  1. /*-
  2.  * See the file LICENSE for redistribution information.
  3.  *
  4.  * Copyright (c) 1999-2002
  5.  * Sleepycat Software.  All rights reserved.
  6.  */
  7. #include "db_config.h"
  8. #ifndef lint
  9. static const char revid[] = "$Id: tcl_db_pkg.c,v 11.141 2002/08/14 20:15:47 bostic Exp $";
  10. #endif /* not lint */
  11. #ifndef NO_SYSTEM_INCLUDES
  12. #include <sys/types.h>
  13. #include <stdlib.h>
  14. #include <string.h>
  15. #include <tcl.h>
  16. #endif
  17. #if CONFIG_TEST
  18. #define DB_DBM_HSEARCH 1
  19. #endif
  20. #include "db_int.h"
  21. #include "dbinc/db_page.h"
  22. #include "dbinc/hash.h"
  23. #include "dbinc/tcl_db.h"
  24. /* XXX we must declare global data in just one place */
  25. DBTCL_GLOBAL __dbtcl_global;
  26. /*
  27.  * Prototypes for procedures defined later in this file:
  28.  */
  29. static int berkdb_Cmd __P((ClientData, Tcl_Interp *, int,
  30.     Tcl_Obj * CONST*));
  31. static int bdb_EnvOpen __P((Tcl_Interp *, int, Tcl_Obj * CONST*,
  32.     DBTCL_INFO *, DB_ENV **));
  33. static int bdb_DbOpen __P((Tcl_Interp *, int, Tcl_Obj * CONST*,
  34.     DBTCL_INFO *, DB **));
  35. static int bdb_DbRemove __P((Tcl_Interp *, int, Tcl_Obj * CONST*));
  36. static int bdb_DbRename __P((Tcl_Interp *, int, Tcl_Obj * CONST*));
  37. static int bdb_DbUpgrade __P((Tcl_Interp *, int, Tcl_Obj * CONST*));
  38. static int bdb_DbVerify __P((Tcl_Interp *, int, Tcl_Obj * CONST*));
  39. static int bdb_Version __P((Tcl_Interp *, int, Tcl_Obj * CONST*));
  40. static int bdb_Handles __P((Tcl_Interp *, int, Tcl_Obj * CONST*));
  41. static int tcl_bt_compare __P((DB *, const DBT *, const DBT *));
  42. static int tcl_compare_callback __P((DB *, const DBT *, const DBT *,
  43.     Tcl_Obj *, char *));
  44. static int tcl_dup_compare __P((DB *, const DBT *, const DBT *));
  45. static u_int32_t tcl_h_hash __P((DB *, const void *, u_int32_t));
  46. static int tcl_rep_send __P((DB_ENV *,
  47.     const DBT *, const DBT *, int, u_int32_t));
  48. #ifdef TEST_ALLOC
  49. static void * tcl_db_malloc __P((size_t));
  50. static void * tcl_db_realloc __P((void *, size_t));
  51. static void tcl_db_free __P((void *));
  52. #endif
  53. /*
  54.  * Db_tcl_Init --
  55.  *
  56.  * This is a package initialization procedure, which is called by Tcl when
  57.  * this package is to be added to an interpreter.  The name is based on the
  58.  * name of the shared library, currently libdb_tcl-X.Y.so, which Tcl uses
  59.  * to determine the name of this function.
  60.  */
  61. int
  62. Db_tcl_Init(interp)
  63. Tcl_Interp *interp; /* Interpreter in which the package is
  64.  * to be made available. */
  65. {
  66. int code;
  67. code = Tcl_PkgProvide(interp, "Db_tcl", "1.0");
  68. if (code != TCL_OK)
  69. return (code);
  70. Tcl_CreateObjCommand(interp, "berkdb", (Tcl_ObjCmdProc *)berkdb_Cmd,
  71.     (ClientData)0, NULL);
  72. /*
  73.  * Create shared global debugging variables
  74.  */
  75. Tcl_LinkVar(interp, "__debug_on", (char *)&__debug_on, TCL_LINK_INT);
  76. Tcl_LinkVar(interp, "__debug_print", (char *)&__debug_print,
  77.     TCL_LINK_INT);
  78. Tcl_LinkVar(interp, "__debug_stop", (char *)&__debug_stop,
  79.     TCL_LINK_INT);
  80. Tcl_LinkVar(interp, "__debug_test", (char *)&__debug_test,
  81.     TCL_LINK_INT);
  82. LIST_INIT(&__db_infohead);
  83. return (TCL_OK);
  84. }
  85. /*
  86.  * berkdb_cmd --
  87.  * Implements the "berkdb" command.
  88.  * This command supports three sub commands:
  89.  * berkdb version - Returns a list {major minor patch}
  90.  * berkdb env - Creates a new DB_ENV and returns a binding
  91.  *   to a new command of the form dbenvX, where X is an
  92.  *   integer starting at 0 (dbenv0, dbenv1, ...)
  93.  * berkdb open - Creates a new DB (optionally within
  94.  *   the given environment.  Returns a binding to a new
  95.  *   command of the form dbX, where X is an integer
  96.  *   starting at 0 (db0, db1, ...)
  97.  */
  98. static int
  99. berkdb_Cmd(notused, interp, objc, objv)
  100. ClientData notused; /* Not used. */
  101. Tcl_Interp *interp; /* Interpreter */
  102. int objc; /* How many arguments? */
  103. Tcl_Obj *CONST objv[]; /* The argument objects */
  104. {
  105. static char *berkdbcmds[] = {
  106. #if CONFIG_TEST
  107. "dbverify",
  108. "handles",
  109. "upgrade",
  110. #endif
  111. "dbremove",
  112. "dbrename",
  113. "env",
  114. "envremove",
  115. "open",
  116. "version",
  117. #if CONFIG_TEST
  118. /* All below are compatibility functions */
  119. "hcreate", "hsearch", "hdestroy",
  120. "dbminit", "fetch", "store",
  121. "delete", "firstkey", "nextkey",
  122. "ndbm_open", "dbmclose",
  123. #endif
  124. /* All below are convenience functions */
  125. "rand", "random_int", "srand",
  126. "debug_check",
  127. NULL
  128. };
  129. /*
  130.  * All commands enums below ending in X are compatibility
  131.  */
  132. enum berkdbcmds {
  133. #if CONFIG_TEST
  134. BDB_DBVERIFY,
  135. BDB_HANDLES,
  136. BDB_UPGRADE,
  137. #endif
  138. BDB_DBREMOVE,
  139. BDB_DBRENAME,
  140. BDB_ENV,
  141. BDB_ENVREMOVE,
  142. BDB_OPEN,
  143. BDB_VERSION,
  144. #if CONFIG_TEST
  145. BDB_HCREATEX, BDB_HSEARCHX, BDB_HDESTROYX,
  146. BDB_DBMINITX, BDB_FETCHX, BDB_STOREX,
  147. BDB_DELETEX, BDB_FIRSTKEYX, BDB_NEXTKEYX,
  148. BDB_NDBMOPENX, BDB_DBMCLOSEX,
  149. #endif
  150. BDB_RANDX, BDB_RAND_INTX, BDB_SRANDX,
  151. BDB_DBGCKX
  152. };
  153. static int env_id = 0;
  154. static int db_id = 0;
  155. DB *dbp;
  156. #if CONFIG_TEST
  157. DBM *ndbmp;
  158. static int ndbm_id = 0;
  159. #endif
  160. DBTCL_INFO *ip;
  161. DB_ENV *envp;
  162. Tcl_Obj *res;
  163. int cmdindex, result;
  164. char newname[MSG_SIZE];
  165. COMPQUIET(notused, NULL);
  166. Tcl_ResetResult(interp);
  167. memset(newname, 0, MSG_SIZE);
  168. result = TCL_OK;
  169. if (objc <= 1) {
  170. Tcl_WrongNumArgs(interp, 1, objv, "command cmdargs");
  171. return (TCL_ERROR);
  172. }
  173. /*
  174.  * Get the command name index from the object based on the berkdbcmds
  175.  * defined above.
  176.  */
  177. if (Tcl_GetIndexFromObj(interp,
  178.     objv[1], berkdbcmds, "command", TCL_EXACT, &cmdindex) != TCL_OK)
  179. return (IS_HELP(objv[1]));
  180. res = NULL;
  181. switch ((enum berkdbcmds)cmdindex) {
  182. #if CONFIG_TEST
  183. case BDB_DBVERIFY:
  184. result = bdb_DbVerify(interp, objc, objv);
  185. break;
  186. case BDB_HANDLES:
  187. result = bdb_Handles(interp, objc, objv);
  188. break;
  189. case BDB_UPGRADE:
  190. result = bdb_DbUpgrade(interp, objc, objv);
  191. break;
  192. #endif
  193. case BDB_VERSION:
  194. _debug_check();
  195. result = bdb_Version(interp, objc, objv);
  196. break;
  197. case BDB_ENV:
  198. snprintf(newname, sizeof(newname), "env%d", env_id);
  199. ip = _NewInfo(interp, NULL, newname, I_ENV);
  200. if (ip != NULL) {
  201. result = bdb_EnvOpen(interp, objc, objv, ip, &envp);
  202. if (result == TCL_OK && envp != NULL) {
  203. env_id++;
  204. Tcl_CreateObjCommand(interp, newname,
  205.     (Tcl_ObjCmdProc *)env_Cmd,
  206.     (ClientData)envp, NULL);
  207. /* Use ip->i_name - newname is overwritten */
  208. res =
  209.     Tcl_NewStringObj(newname, strlen(newname));
  210. _SetInfoData(ip, envp);
  211. } else
  212. _DeleteInfo(ip);
  213. } else {
  214. Tcl_SetResult(interp, "Could not set up info",
  215.     TCL_STATIC);
  216. result = TCL_ERROR;
  217. }
  218. break;
  219. case BDB_DBREMOVE:
  220. result = bdb_DbRemove(interp, objc, objv);
  221. break;
  222. case BDB_DBRENAME:
  223. result = bdb_DbRename(interp, objc, objv);
  224. break;
  225. case BDB_ENVREMOVE:
  226. result = tcl_EnvRemove(interp, objc, objv, NULL, NULL);
  227. break;
  228. case BDB_OPEN:
  229. snprintf(newname, sizeof(newname), "db%d", db_id);
  230. ip = _NewInfo(interp, NULL, newname, I_DB);
  231. if (ip != NULL) {
  232. result = bdb_DbOpen(interp, objc, objv, ip, &dbp);
  233. if (result == TCL_OK && dbp != NULL) {
  234. db_id++;
  235. Tcl_CreateObjCommand(interp, newname,
  236.     (Tcl_ObjCmdProc *)db_Cmd,
  237.     (ClientData)dbp, NULL);
  238. /* Use ip->i_name - newname is overwritten */
  239. res =
  240.     Tcl_NewStringObj(newname, strlen(newname));
  241. _SetInfoData(ip, dbp);
  242. } else
  243. _DeleteInfo(ip);
  244. } else {
  245. Tcl_SetResult(interp, "Could not set up info",
  246.     TCL_STATIC);
  247. result = TCL_ERROR;
  248. }
  249. break;
  250. #if CONFIG_TEST
  251. case BDB_HCREATEX:
  252. case BDB_HSEARCHX:
  253. case BDB_HDESTROYX:
  254. result = bdb_HCommand(interp, objc, objv);
  255. break;
  256. case BDB_DBMINITX:
  257. case BDB_DBMCLOSEX:
  258. case BDB_FETCHX:
  259. case BDB_STOREX:
  260. case BDB_DELETEX:
  261. case BDB_FIRSTKEYX:
  262. case BDB_NEXTKEYX:
  263. result = bdb_DbmCommand(interp, objc, objv, DBTCL_DBM, NULL);
  264. break;
  265. case BDB_NDBMOPENX:
  266. snprintf(newname, sizeof(newname), "ndbm%d", ndbm_id);
  267. ip = _NewInfo(interp, NULL, newname, I_NDBM);
  268. if (ip != NULL) {
  269. result = bdb_NdbmOpen(interp, objc, objv, &ndbmp);
  270. if (result == TCL_OK) {
  271. ndbm_id++;
  272. Tcl_CreateObjCommand(interp, newname,
  273.     (Tcl_ObjCmdProc *)ndbm_Cmd,
  274.     (ClientData)ndbmp, NULL);
  275. /* Use ip->i_name - newname is overwritten */
  276. res =
  277.     Tcl_NewStringObj(newname, strlen(newname));
  278. _SetInfoData(ip, ndbmp);
  279. } else
  280. _DeleteInfo(ip);
  281. } else {
  282. Tcl_SetResult(interp, "Could not set up info",
  283.     TCL_STATIC);
  284. result = TCL_ERROR;
  285. }
  286. break;
  287. #endif
  288. case BDB_RANDX:
  289. case BDB_RAND_INTX:
  290. case BDB_SRANDX:
  291. result = bdb_RandCommand(interp, objc, objv);
  292. break;
  293. case BDB_DBGCKX:
  294. _debug_check();
  295. res = Tcl_NewIntObj(0);
  296. break;
  297. }
  298. /*
  299.  * For each different arg call different function to create
  300.  * new commands (or if version, get/return it).
  301.  */
  302. if (result == TCL_OK && res != NULL)
  303. Tcl_SetObjResult(interp, res);
  304. return (result);
  305. }
  306. /*
  307.  * bdb_EnvOpen -
  308.  * Implements the environment open command.
  309.  * There are many, many options to the open command.
  310.  * Here is the general flow:
  311.  *
  312.  * 1.  Call db_env_create to create the env handle.
  313.  * 2.  Parse args tracking options.
  314.  * 3.  Make any pre-open setup calls necessary.
  315.  * 4.  Call DB_ENV->open to open the env.
  316.  * 5.  Return env widget handle to user.
  317.  */
  318. static int
  319. bdb_EnvOpen(interp, objc, objv, ip, env)
  320. Tcl_Interp *interp; /* Interpreter */
  321. int objc; /* How many arguments? */
  322. Tcl_Obj *CONST objv[]; /* The argument objects */
  323. DBTCL_INFO *ip; /* Our internal info */
  324. DB_ENV **env; /* Environment pointer */
  325. {
  326. static char *envopen[] = {
  327. #if CONFIG_TEST
  328. "-auto_commit",
  329. "-cdb",
  330. "-cdb_alldb",
  331. "-client_timeout",
  332. "-lock",
  333. "-lock_conflict",
  334. "-lock_detect",
  335. "-lock_max",
  336. "-lock_max_locks",
  337. "-lock_max_lockers",
  338. "-lock_max_objects",
  339. "-lock_timeout",
  340. "-log",
  341. "-log_buffer",
  342. "-log_max",
  343. "-log_regionmax",
  344. "-mmapsize",
  345. "-nommap",
  346. "-overwrite",
  347. "-region_init",
  348. "-rep_client",
  349. "-rep_logsonly",
  350. "-rep_master",
  351. "-rep_transport",
  352. "-server",
  353. "-server_timeout",
  354. "-txn_timeout",
  355. "-txn_timestamp",
  356. "-verbose",
  357. "-wrnosync",
  358. #endif
  359. "-cachesize",
  360. "-create",
  361. "-data_dir",
  362. "-encryptaes",
  363. "-encryptany",
  364. "-errfile",
  365. "-errpfx",
  366. "-home",
  367. "-log_dir",
  368. "-mode",
  369. "-private",
  370. "-recover",
  371. "-recover_fatal",
  372. "-shm_key",
  373. "-system_mem",
  374. "-tmp_dir",
  375. "-txn",
  376. "-txn_max",
  377. "-use_environ",
  378. "-use_environ_root",
  379. NULL
  380. };
  381. /*
  382.  * !!!
  383.  * These have to be in the same order as the above,
  384.  * which is close to but not quite alphabetical.
  385.  */
  386. enum envopen {
  387. #if CONFIG_TEST
  388. ENV_AUTO_COMMIT,
  389. ENV_CDB,
  390. ENV_CDB_ALLDB,
  391. ENV_CLIENT_TO,
  392. ENV_LOCK,
  393. ENV_CONFLICT,
  394. ENV_DETECT,
  395. ENV_LOCK_MAX,
  396. ENV_LOCK_MAX_LOCKS,
  397. ENV_LOCK_MAX_LOCKERS,
  398. ENV_LOCK_MAX_OBJECTS,
  399. ENV_LOCK_TIMEOUT,
  400. ENV_LOG,
  401. ENV_LOG_BUFFER,
  402. ENV_LOG_MAX,
  403. ENV_LOG_REGIONMAX,
  404. ENV_MMAPSIZE,
  405. ENV_NOMMAP,
  406. ENV_OVERWRITE,
  407. ENV_REGION_INIT,
  408. ENV_REP_CLIENT,
  409. ENV_REP_LOGSONLY,
  410. ENV_REP_MASTER,
  411. ENV_REP_TRANSPORT,
  412. ENV_SERVER,
  413. ENV_SERVER_TO,
  414. ENV_TXN_TIMEOUT,
  415. ENV_TXN_TIME,
  416. ENV_VERBOSE,
  417. ENV_WRNOSYNC,
  418. #endif
  419. ENV_CACHESIZE,
  420. ENV_CREATE,
  421. ENV_DATA_DIR,
  422. ENV_ENCRYPT_AES,
  423. ENV_ENCRYPT_ANY,
  424. ENV_ERRFILE,
  425. ENV_ERRPFX,
  426. ENV_HOME,
  427. ENV_LOG_DIR,
  428. ENV_MODE,
  429. ENV_PRIVATE,
  430. ENV_RECOVER,
  431. ENV_RECOVER_FATAL,
  432. ENV_SHM_KEY,
  433. ENV_SYSTEM_MEM,
  434. ENV_TMP_DIR,
  435. ENV_TXN,
  436. ENV_TXN_MAX,
  437. ENV_USE_ENVIRON,
  438. ENV_USE_ENVIRON_ROOT
  439. };
  440. Tcl_Obj **myobjv, **myobjv1;
  441. time_t timestamp;
  442. u_int32_t detect, gbytes, bytes, ncaches, logbufset, logmaxset;
  443. u_int32_t open_flags, rep_flags, set_flags, size, uintarg;
  444. u_int8_t *conflicts;
  445. int i, intarg, j, mode, myobjc, nmodes, optindex;
  446. int result, ret, temp;
  447. long client_to, server_to, shm;
  448. char *arg, *home, *passwd, *server;
  449. result = TCL_OK;
  450. mode = 0;
  451. rep_flags = set_flags = 0;
  452. home = NULL;
  453. /*
  454.  * XXX
  455.  * If/when our Tcl interface becomes thread-safe, we should enable
  456.  * DB_THREAD here in all cases.  For now, turn it on only when testing
  457.  * so that we exercise MUTEX_THREAD_LOCK cases.
  458.  *
  459.  * Historically, a key stumbling block was the log_get interface,
  460.  * which could only do relative operations in a non-threaded
  461.  * environment.  This is no longer an issue, thanks to log cursors,
  462.  * but we need to look at making sure DBTCL_INFO structs
  463.  * are safe to share across threads (they're not mutex-protected)
  464.  * before we declare the Tcl interface thread-safe.  Meanwhile,
  465.  * there's no strong reason to enable DB_THREAD.
  466.  */
  467. open_flags = DB_JOINENV |
  468. #ifdef TEST_THREAD
  469.     DB_THREAD;
  470. #else
  471.     0;
  472. #endif
  473. logmaxset = logbufset = 0;
  474. if (objc <= 2) {
  475. Tcl_WrongNumArgs(interp, 2, objv, "?args?");
  476. return (TCL_ERROR);
  477. }
  478. /*
  479.  * Server code must go before the call to db_env_create.
  480.  */
  481. server = NULL;
  482. server_to = client_to = 0;
  483. i = 2;
  484. while (i < objc) {
  485. if (Tcl_GetIndexFromObj(interp, objv[i++], envopen, "option",
  486.     TCL_EXACT, &optindex) != TCL_OK) {
  487. Tcl_ResetResult(interp);
  488. continue;
  489. }
  490. switch ((enum envopen)optindex) {
  491. #if CONFIG_TEST
  492. case ENV_SERVER:
  493. if (i >= objc) {
  494. Tcl_WrongNumArgs(interp, 2, objv,
  495.     "?-server hostname");
  496. result = TCL_ERROR;
  497. break;
  498. }
  499. server = Tcl_GetStringFromObj(objv[i++], NULL);
  500. break;
  501. case ENV_SERVER_TO:
  502. if (i >= objc) {
  503. Tcl_WrongNumArgs(interp, 2, objv,
  504.     "?-server_to secs");
  505. result = TCL_ERROR;
  506. break;
  507. }
  508. result = Tcl_GetLongFromObj(interp, objv[i++],
  509.     &server_to);
  510. break;
  511. case ENV_CLIENT_TO:
  512. if (i >= objc) {
  513. Tcl_WrongNumArgs(interp, 2, objv,
  514.     "?-client_to secs");
  515. result = TCL_ERROR;
  516. break;
  517. }
  518. result = Tcl_GetLongFromObj(interp, objv[i++],
  519.     &client_to);
  520. break;
  521. #endif
  522. default:
  523. break;
  524. }
  525. }
  526. if (server != NULL) {
  527. ret = db_env_create(env, DB_CLIENT);
  528. if (ret)
  529. return (_ReturnSetup(interp, ret, DB_RETOK_STD(ret),
  530.     "db_env_create"));
  531. (*env)->set_errpfx((*env), ip->i_name);
  532. (*env)->set_errcall((*env), _ErrorFunc);
  533. if ((ret = (*env)->set_rpc_server((*env), NULL, server,
  534.     client_to, server_to, 0)) != 0) {
  535. result = TCL_ERROR;
  536. goto error;
  537. }
  538. } else {
  539. /*
  540.  * Create the environment handle before parsing the args
  541.  * since we'll be modifying the environment as we parse.
  542.  */
  543. ret = db_env_create(env, 0);
  544. if (ret)
  545. return (_ReturnSetup(interp, ret, DB_RETOK_STD(ret),
  546.     "db_env_create"));
  547. (*env)->set_errpfx((*env), ip->i_name);
  548. (*env)->set_errcall((*env), _ErrorFunc);
  549. }
  550. /* Hang our info pointer on the env handle, so we can do callbacks. */
  551. (*env)->app_private = ip;
  552. /*
  553.  * Use a Tcl-local alloc and free function so that we're sure to
  554.  * test whether we use umalloc/ufree in the right places.
  555.  */
  556. #ifdef TEST_ALLOC
  557. (*env)->set_alloc(*env, tcl_db_malloc, tcl_db_realloc, tcl_db_free);
  558. #endif
  559. /*
  560.  * Get the command name index from the object based on the bdbcmds
  561.  * defined above.
  562.  */
  563. i = 2;
  564. while (i < objc) {
  565. Tcl_ResetResult(interp);
  566. if (Tcl_GetIndexFromObj(interp, objv[i], envopen, "option",
  567.     TCL_EXACT, &optindex) != TCL_OK) {
  568. result = IS_HELP(objv[i]);
  569. goto error;
  570. }
  571. i++;
  572. switch ((enum envopen)optindex) {
  573. #if CONFIG_TEST
  574. case ENV_SERVER:
  575. case ENV_SERVER_TO:
  576. case ENV_CLIENT_TO:
  577. /*
  578.  * Already handled these, skip them and their arg.
  579.  */
  580. i++;
  581. break;
  582. case ENV_AUTO_COMMIT:
  583. FLD_SET(set_flags, DB_AUTO_COMMIT);
  584. break;
  585. case ENV_CDB:
  586. FLD_SET(open_flags, DB_INIT_CDB | DB_INIT_MPOOL);
  587. FLD_CLR(open_flags, DB_JOINENV);
  588. break;
  589. case ENV_CDB_ALLDB:
  590. FLD_SET(set_flags, DB_CDB_ALLDB);
  591. break;
  592. case ENV_LOCK:
  593. FLD_SET(open_flags, DB_INIT_LOCK | DB_INIT_MPOOL);
  594. FLD_CLR(open_flags, DB_JOINENV);
  595. break;
  596. case ENV_CONFLICT:
  597. /*
  598.  * Get conflict list.  List is:
  599.  * {nmodes {matrix}}
  600.  *
  601.  * Where matrix must be nmodes*nmodes big.
  602.  * Set up conflicts array to pass.
  603.  */
  604. result = Tcl_ListObjGetElements(interp, objv[i],
  605.     &myobjc, &myobjv);
  606. if (result == TCL_OK)
  607. i++;
  608. else
  609. break;
  610. if (myobjc != 2) {
  611. Tcl_WrongNumArgs(interp, 2, objv,
  612.     "?-lock_conflict {nmodes {matrix}}?");
  613. result = TCL_ERROR;
  614. break;
  615. }
  616. result = Tcl_GetIntFromObj(interp, myobjv[0], &nmodes);
  617. if (result != TCL_OK)
  618. break;
  619. result = Tcl_ListObjGetElements(interp, myobjv[1],
  620.     &myobjc, &myobjv1);
  621. if (myobjc != (nmodes * nmodes)) {
  622. Tcl_WrongNumArgs(interp, 2, objv,
  623.     "?-lock_conflict {nmodes {matrix}}?");
  624. result = TCL_ERROR;
  625. break;
  626. }
  627. size = sizeof(u_int8_t) * nmodes*nmodes;
  628. ret = __os_malloc(*env, size, &conflicts);
  629. if (ret != 0) {
  630. result = TCL_ERROR;
  631. break;
  632. }
  633. for (j = 0; j < myobjc; j++) {
  634. result = Tcl_GetIntFromObj(interp, myobjv1[j],
  635.     &temp);
  636. conflicts[j] = temp;
  637. if (result != TCL_OK) {
  638. __os_free(NULL, conflicts);
  639. break;
  640. }
  641. }
  642. _debug_check();
  643. ret = (*env)->set_lk_conflicts(*env,
  644.     (u_int8_t *)conflicts, nmodes);
  645. __os_free(NULL, conflicts);
  646. result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
  647.     "set_lk_conflicts");
  648. break;
  649. case ENV_DETECT:
  650. if (i >= objc) {
  651. Tcl_WrongNumArgs(interp, 2, objv,
  652.     "?-lock_detect policy?");
  653. result = TCL_ERROR;
  654. break;
  655. }
  656. arg = Tcl_GetStringFromObj(objv[i++], NULL);
  657. if (strcmp(arg, "default") == 0)
  658. detect = DB_LOCK_DEFAULT;
  659. else if (strcmp(arg, "expire") == 0)
  660. detect = DB_LOCK_EXPIRE;
  661. else if (strcmp(arg, "maxlocks") == 0)
  662. detect = DB_LOCK_MAXLOCKS;
  663. else if (strcmp(arg, "minlocks") == 0)
  664. detect = DB_LOCK_MINLOCKS;
  665. else if (strcmp(arg, "minwrites") == 0)
  666. detect = DB_LOCK_MINWRITE;
  667. else if (strcmp(arg, "oldest") == 0)
  668. detect = DB_LOCK_OLDEST;
  669. else if (strcmp(arg, "youngest") == 0)
  670. detect = DB_LOCK_YOUNGEST;
  671. else if (strcmp(arg, "random") == 0)
  672. detect = DB_LOCK_RANDOM;
  673. else {
  674. Tcl_AddErrorInfo(interp,
  675.     "lock_detect: illegal policy");
  676. result = TCL_ERROR;
  677. break;
  678. }
  679. _debug_check();
  680. ret = (*env)->set_lk_detect(*env, detect);
  681. result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
  682.     "lock_detect");
  683. break;
  684. case ENV_LOCK_MAX:
  685. case ENV_LOCK_MAX_LOCKS:
  686. case ENV_LOCK_MAX_LOCKERS:
  687. case ENV_LOCK_MAX_OBJECTS:
  688. if (i >= objc) {
  689. Tcl_WrongNumArgs(interp, 2, objv,
  690.     "?-lock_max max?");
  691. result = TCL_ERROR;
  692. break;
  693. }
  694. result = _GetUInt32(interp, objv[i++], &uintarg);
  695. if (result == TCL_OK) {
  696. _debug_check();
  697. switch ((enum envopen)optindex) {
  698. case ENV_LOCK_MAX:
  699. ret = (*env)->set_lk_max(*env,
  700.     uintarg);
  701. break;
  702. case ENV_LOCK_MAX_LOCKS:
  703. ret = (*env)->set_lk_max_locks(*env,
  704.     uintarg);
  705. break;
  706. case ENV_LOCK_MAX_LOCKERS:
  707. ret = (*env)->set_lk_max_lockers(*env,
  708.     uintarg);
  709. break;
  710. case ENV_LOCK_MAX_OBJECTS:
  711. ret = (*env)->set_lk_max_objects(*env,
  712.     uintarg);
  713. break;
  714. default:
  715. break;
  716. }
  717. result = _ReturnSetup(interp, ret,
  718.     DB_RETOK_STD(ret), "lock_max");
  719. }
  720. break;
  721. case ENV_TXN_TIME:
  722. case ENV_TXN_TIMEOUT:
  723. case ENV_LOCK_TIMEOUT:
  724. if (i >= objc) {
  725. Tcl_WrongNumArgs(interp, 2, objv,
  726.     "?-txn_timestamp time?");
  727. result = TCL_ERROR;
  728. break;
  729. }
  730. result = Tcl_GetLongFromObj(interp, objv[i++],
  731.     (long *)&timestamp);
  732. if (result == TCL_OK) {
  733. _debug_check();
  734. if (optindex == ENV_TXN_TIME)
  735. ret = (*env)->
  736.     set_tx_timestamp(*env, &timestamp);
  737. else
  738. ret = (*env)->set_timeout(*env,
  739.     (db_timeout_t)timestamp,
  740.     optindex == ENV_TXN_TIMEOUT ?
  741.     DB_SET_TXN_TIMEOUT :
  742.     DB_SET_LOCK_TIMEOUT);
  743. result = _ReturnSetup(interp, ret,
  744.     DB_RETOK_STD(ret), "txn_timestamp");
  745. }
  746. break;
  747. case ENV_LOG:
  748. FLD_SET(open_flags, DB_INIT_LOG | DB_INIT_MPOOL);
  749. FLD_CLR(open_flags, DB_JOINENV);
  750. break;
  751. case ENV_LOG_BUFFER:
  752. if (i >= objc) {
  753. Tcl_WrongNumArgs(interp, 2, objv,
  754.     "?-log_buffer size?");
  755. result = TCL_ERROR;
  756. break;
  757. }
  758. result = _GetUInt32(interp, objv[i++], &uintarg);
  759. if (result == TCL_OK) {
  760. _debug_check();
  761. ret = (*env)->set_lg_bsize(*env, uintarg);
  762. result = _ReturnSetup(interp, ret,
  763.     DB_RETOK_STD(ret), "log_bsize");
  764. logbufset = 1;
  765. if (logmaxset) {
  766. _debug_check();
  767. ret = (*env)->set_lg_max(*env,
  768.     logmaxset);
  769. result = _ReturnSetup(interp, ret,
  770.     DB_RETOK_STD(ret), "log_max");
  771. logmaxset = 0;
  772. logbufset = 0;
  773. }
  774. }
  775. break;
  776. case ENV_LOG_MAX:
  777. if (i >= objc) {
  778. Tcl_WrongNumArgs(interp, 2, objv,
  779.     "?-log_max max?");
  780. result = TCL_ERROR;
  781. break;
  782. }
  783. result = _GetUInt32(interp, objv[i++], &uintarg);
  784. if (result == TCL_OK && logbufset) {
  785. _debug_check();
  786. ret = (*env)->set_lg_max(*env, uintarg);
  787. result = _ReturnSetup(interp, ret,
  788.     DB_RETOK_STD(ret), "log_max");
  789. logbufset = 0;
  790. } else
  791. logmaxset = uintarg;
  792. break;
  793. case ENV_LOG_REGIONMAX:
  794. if (i >= objc) {
  795. Tcl_WrongNumArgs(interp, 2, objv,
  796.     "?-log_regionmax size?");
  797. result = TCL_ERROR;
  798. break;
  799. }
  800. result = _GetUInt32(interp, objv[i++], &uintarg);
  801. if (result == TCL_OK) {
  802. _debug_check();
  803. ret = (*env)->set_lg_regionmax(*env, uintarg);
  804. result =
  805.     _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
  806. "log_regionmax");
  807. }
  808. break;
  809. case ENV_MMAPSIZE:
  810. if (i >= objc) {
  811. Tcl_WrongNumArgs(interp, 2, objv,
  812.     "?-mmapsize size?");
  813. result = TCL_ERROR;
  814. break;
  815. }
  816. result = Tcl_GetIntFromObj(interp, objv[i++], &intarg);
  817. if (result == TCL_OK) {
  818. _debug_check();
  819. ret = (*env)->set_mp_mmapsize(*env,
  820.     (size_t)intarg);
  821. result = _ReturnSetup(interp, ret,
  822.     DB_RETOK_STD(ret), "mmapsize");
  823. }
  824. break;
  825. case ENV_NOMMAP:
  826. FLD_SET(set_flags, DB_NOMMAP);
  827. break;
  828. case ENV_OVERWRITE:
  829. FLD_SET(set_flags, DB_OVERWRITE);
  830. break;
  831. case ENV_REGION_INIT:
  832. _debug_check();
  833. ret = (*env)->set_flags(*env, DB_REGION_INIT, 1);
  834. result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
  835.     "region_init");
  836. break;
  837. case ENV_REP_CLIENT:
  838. rep_flags = DB_REP_CLIENT;
  839. break;
  840. case ENV_REP_LOGSONLY:
  841. rep_flags = DB_REP_LOGSONLY;
  842. break;
  843. case ENV_REP_MASTER:
  844. rep_flags = DB_REP_MASTER;
  845. break;
  846. case ENV_REP_TRANSPORT:
  847. if (i >= objc) {
  848. Tcl_WrongNumArgs(interp, 2, objv,
  849.     "-rep_transport {envid sendproc}");
  850. result = TCL_ERROR;
  851. break;
  852. }
  853. /*
  854.  * Store the objects containing the machine ID
  855.  * and the procedure name.  We don't need to crack
  856.  * the send procedure out now, but we do convert the
  857.  * machine ID to an int, since set_rep_transport needs
  858.  * it.  Even so, it'll be easier later to deal with
  859.  * the Tcl_Obj *, so we save that, not the int.
  860.  *
  861.  * Note that we Tcl_IncrRefCount both objects
  862.  * independently;  Tcl is free to discard the list
  863.  * that they're bundled into.
  864.  */
  865. result = Tcl_ListObjGetElements(interp, objv[i++],
  866.     &myobjc, &myobjv);
  867. if (myobjc != 2) {
  868. Tcl_SetResult(interp,
  869.     "List must be {envid sendproc}",
  870.     TCL_STATIC);
  871. result = TCL_ERROR;
  872. break;
  873. }
  874. /*
  875.  * Check that the machine ID is an int.  Note that
  876.  * we do want to use GetIntFromObj;  the machine
  877.  * ID is explicitly an int, not a u_int32_t.
  878.  */
  879. ip->i_rep_eid = myobjv[0];
  880. Tcl_IncrRefCount(ip->i_rep_eid);
  881. result = Tcl_GetIntFromObj(interp,
  882.     ip->i_rep_eid, &intarg);
  883. if (result != TCL_OK)
  884. break;
  885. ip->i_rep_send = myobjv[1];
  886. Tcl_IncrRefCount(ip->i_rep_send);
  887. _debug_check();
  888. ret = (*env)->set_rep_transport(*env,
  889.     intarg, tcl_rep_send);
  890. result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
  891.     "set_rep_transport");
  892. break;
  893. case ENV_VERBOSE:
  894. result = Tcl_ListObjGetElements(interp, objv[i],
  895.     &myobjc, &myobjv);
  896. if (result == TCL_OK)
  897. i++;
  898. else
  899. break;
  900. if (myobjc != 2) {
  901. Tcl_WrongNumArgs(interp, 2, objv,
  902.     "?-verbose {which on|off}?");
  903. result = TCL_ERROR;
  904. break;
  905. }
  906. result = tcl_EnvVerbose(interp, *env,
  907.     myobjv[0], myobjv[1]);
  908. break;
  909. case ENV_WRNOSYNC:
  910. FLD_SET(set_flags, DB_TXN_WRITE_NOSYNC);
  911. break;
  912. #endif
  913. case ENV_TXN:
  914. FLD_SET(open_flags, DB_INIT_LOCK |
  915.     DB_INIT_LOG | DB_INIT_MPOOL | DB_INIT_TXN);
  916. FLD_CLR(open_flags, DB_JOINENV);
  917. /* Make sure we have an arg to check against! */
  918. if (i < objc) {
  919. arg = Tcl_GetStringFromObj(objv[i], NULL);
  920. if (strcmp(arg, "nosync") == 0) {
  921. FLD_SET(set_flags, DB_TXN_NOSYNC);
  922. i++;
  923. }
  924. }
  925. break;
  926. case ENV_CREATE:
  927. FLD_SET(open_flags, DB_CREATE | DB_INIT_MPOOL);
  928. FLD_CLR(open_flags, DB_JOINENV);
  929. break;
  930. case ENV_ENCRYPT_AES:
  931. /* Make sure we have an arg to check against! */
  932. if (i >= objc) {
  933. Tcl_WrongNumArgs(interp, 2, objv,
  934.     "?-encryptaes passwd?");
  935. result = TCL_ERROR;
  936. break;
  937. }
  938. passwd = Tcl_GetStringFromObj(objv[i++], NULL);
  939. _debug_check();
  940. ret = (*env)->set_encrypt(*env, passwd, DB_ENCRYPT_AES);
  941. result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
  942.     "set_encrypt");
  943. break;
  944. case ENV_ENCRYPT_ANY:
  945. /* Make sure we have an arg to check against! */
  946. if (i >= objc) {
  947. Tcl_WrongNumArgs(interp, 2, objv,
  948.     "?-encryptany passwd?");
  949. result = TCL_ERROR;
  950. break;
  951. }
  952. passwd = Tcl_GetStringFromObj(objv[i++], NULL);
  953. _debug_check();
  954. ret = (*env)->set_encrypt(*env, passwd, 0);
  955. result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
  956.     "set_encrypt");
  957. break;
  958. case ENV_HOME:
  959. /* Make sure we have an arg to check against! */
  960. if (i >= objc) {
  961. Tcl_WrongNumArgs(interp, 2, objv,
  962.     "?-home dir?");
  963. result = TCL_ERROR;
  964. break;
  965. }
  966. home = Tcl_GetStringFromObj(objv[i++], NULL);
  967. break;
  968. case ENV_MODE:
  969. if (i >= objc) {
  970. Tcl_WrongNumArgs(interp, 2, objv,
  971.     "?-mode mode?");
  972. result = TCL_ERROR;
  973. break;
  974. }
  975. /*
  976.  * Don't need to check result here because
  977.  * if TCL_ERROR, the error message is already
  978.  * set up, and we'll bail out below.  If ok,
  979.  * the mode is set and we go on.
  980.  */
  981. result = Tcl_GetIntFromObj(interp, objv[i++], &mode);
  982. break;
  983. case ENV_PRIVATE:
  984. FLD_SET(open_flags, DB_PRIVATE | DB_INIT_MPOOL);
  985. FLD_CLR(open_flags, DB_JOINENV);
  986. break;
  987. case ENV_RECOVER:
  988. FLD_SET(open_flags, DB_RECOVER);
  989. break;
  990. case ENV_RECOVER_FATAL:
  991. FLD_SET(open_flags, DB_RECOVER_FATAL);
  992. break;
  993. case ENV_SYSTEM_MEM:
  994. FLD_SET(open_flags, DB_SYSTEM_MEM);
  995. break;
  996. case ENV_USE_ENVIRON_ROOT:
  997. FLD_SET(open_flags, DB_USE_ENVIRON_ROOT);
  998. break;
  999. case ENV_USE_ENVIRON:
  1000. FLD_SET(open_flags, DB_USE_ENVIRON);
  1001. break;
  1002. case ENV_CACHESIZE:
  1003. result = Tcl_ListObjGetElements(interp, objv[i],
  1004.     &myobjc, &myobjv);
  1005. if (result == TCL_OK)
  1006. i++;
  1007. else
  1008. break;
  1009. if (myobjc != 3) {
  1010. Tcl_WrongNumArgs(interp, 2, objv,
  1011.     "?-cachesize {gbytes bytes ncaches}?");
  1012. result = TCL_ERROR;
  1013. break;
  1014. }
  1015. result = _GetUInt32(interp, myobjv[0], &gbytes);
  1016. if (result != TCL_OK)
  1017. break;
  1018. result = _GetUInt32(interp, myobjv[1], &bytes);
  1019. if (result != TCL_OK)
  1020. break;
  1021. result = _GetUInt32(interp, myobjv[2], &ncaches);
  1022. if (result != TCL_OK)
  1023. break;
  1024. _debug_check();
  1025. ret = (*env)->set_cachesize(*env, gbytes, bytes,
  1026.     ncaches);
  1027. result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
  1028.     "set_cachesize");
  1029. break;
  1030. case ENV_SHM_KEY:
  1031. if (i >= objc) {
  1032. Tcl_WrongNumArgs(interp, 2, objv,
  1033.     "?-shm_key key?");
  1034. result = TCL_ERROR;
  1035. break;
  1036. }
  1037. result = Tcl_GetLongFromObj(interp, objv[i++], &shm);
  1038. if (result == TCL_OK) {
  1039. _debug_check();
  1040. ret = (*env)->set_shm_key(*env, shm);
  1041. result = _ReturnSetup(interp, ret,
  1042.     DB_RETOK_STD(ret), "shm_key");
  1043. }
  1044. break;
  1045. case ENV_TXN_MAX:
  1046. if (i >= objc) {
  1047. Tcl_WrongNumArgs(interp, 2, objv,
  1048.     "?-txn_max max?");
  1049. result = TCL_ERROR;
  1050. break;
  1051. }
  1052. result = _GetUInt32(interp, objv[i++], &uintarg);
  1053. if (result == TCL_OK) {
  1054. _debug_check();
  1055. ret = (*env)->set_tx_max(*env, uintarg);
  1056. result = _ReturnSetup(interp, ret,
  1057.     DB_RETOK_STD(ret), "txn_max");
  1058. }
  1059. break;
  1060. case ENV_ERRFILE:
  1061. if (i >= objc) {
  1062. Tcl_WrongNumArgs(interp, 2, objv,
  1063.     "-errfile file");
  1064. result = TCL_ERROR;
  1065. break;
  1066. }
  1067. arg = Tcl_GetStringFromObj(objv[i++], NULL);
  1068. /*
  1069.  * If the user already set one, close it.
  1070.  */
  1071. if (ip->i_err != NULL)
  1072. fclose(ip->i_err);
  1073. ip->i_err = fopen(arg, "a");
  1074. if (ip->i_err != NULL) {
  1075. _debug_check();
  1076. (*env)->set_errfile(*env, ip->i_err);
  1077. }
  1078. break;
  1079. case ENV_ERRPFX:
  1080. if (i >= objc) {
  1081. Tcl_WrongNumArgs(interp, 2, objv,
  1082.     "-errpfx prefix");
  1083. result = TCL_ERROR;
  1084. break;
  1085. }
  1086. arg = Tcl_GetStringFromObj(objv[i++], NULL);
  1087. /*
  1088.  * If the user already set one, free it.
  1089.  */
  1090. if (ip->i_errpfx != NULL)
  1091. __os_free(NULL, ip->i_errpfx);
  1092. if ((ret =
  1093.     __os_strdup(*env, arg, &ip->i_errpfx)) != 0) {
  1094. result = _ReturnSetup(interp, ret,
  1095.     DB_RETOK_STD(ret), "__os_strdup");
  1096. break;
  1097. }
  1098. if (ip->i_errpfx != NULL) {
  1099. _debug_check();
  1100. (*env)->set_errpfx(*env, ip->i_errpfx);
  1101. }
  1102. break;
  1103. case ENV_DATA_DIR:
  1104. if (i >= objc) {
  1105. Tcl_WrongNumArgs(interp, 2, objv,
  1106.     "-data_dir dir");
  1107. result = TCL_ERROR;
  1108. break;
  1109. }
  1110. arg = Tcl_GetStringFromObj(objv[i++], NULL);
  1111. _debug_check();
  1112. ret = (*env)->set_data_dir(*env, arg);
  1113. result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
  1114.     "set_data_dir");
  1115. break;
  1116. case ENV_LOG_DIR:
  1117. if (i >= objc) {
  1118. Tcl_WrongNumArgs(interp, 2, objv,
  1119.     "-log_dir dir");
  1120. result = TCL_ERROR;
  1121. break;
  1122. }
  1123. arg = Tcl_GetStringFromObj(objv[i++], NULL);
  1124. _debug_check();
  1125. ret = (*env)->set_lg_dir(*env, arg);
  1126. result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
  1127.     "set_lg_dir");
  1128. break;
  1129. case ENV_TMP_DIR:
  1130. if (i >= objc) {
  1131. Tcl_WrongNumArgs(interp, 2, objv,
  1132.     "-tmp_dir dir");
  1133. result = TCL_ERROR;
  1134. break;
  1135. }
  1136. arg = Tcl_GetStringFromObj(objv[i++], NULL);
  1137. _debug_check();
  1138. ret = (*env)->set_tmp_dir(*env, arg);
  1139. result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
  1140.     "set_tmp_dir");
  1141. break;
  1142. }
  1143. /*
  1144.  * If, at any time, parsing the args we get an error,
  1145.  * bail out and return.
  1146.  */
  1147. if (result != TCL_OK)
  1148. goto error;
  1149. }
  1150. /*
  1151.  * We have to check this here.  We want to set the log buffer
  1152.  * size first, if it is specified.  So if the user did so,
  1153.  * then we took care of it above.  But, if we get out here and
  1154.  * logmaxset is non-zero, then they set the log_max without
  1155.  * resetting the log buffer size, so we now have to do the
  1156.  * call to set_lg_max, since we didn't do it above.
  1157.  */
  1158. if (logmaxset) {
  1159. _debug_check();
  1160. ret = (*env)->set_lg_max(*env, (u_int32_t)logmaxset);
  1161. result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
  1162.     "log_max");
  1163. }
  1164. if (result != TCL_OK)
  1165. goto error;
  1166. if (set_flags) {
  1167. ret = (*env)->set_flags(*env, set_flags, 1);
  1168. result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
  1169.     "set_flags");
  1170. if (result == TCL_ERROR)
  1171. goto error;
  1172. /*
  1173.  * If we are successful, clear the result so that the
  1174.  * return from set_flags isn't part of the result.
  1175.  */
  1176. Tcl_ResetResult(interp);
  1177. }
  1178. /*
  1179.  * When we get here, we have already parsed all of our args
  1180.  * and made all our calls to set up the environment.  Everything
  1181.  * is okay so far, no errors, if we get here.
  1182.  *
  1183.  * Now open the environment.
  1184.  */
  1185. _debug_check();
  1186. ret = (*env)->open(*env, home, open_flags, mode);
  1187. result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "env open");
  1188. if (rep_flags != 0 && result == TCL_OK) {
  1189. _debug_check();
  1190. ret = (*env)->rep_start(*env, NULL, rep_flags);
  1191. result = _ReturnSetup(interp,
  1192.     ret, DB_RETOK_STD(ret), "rep_start");
  1193. }
  1194. error: if (result == TCL_ERROR) {
  1195. if (ip->i_err) {
  1196. fclose(ip->i_err);
  1197. ip->i_err = NULL;
  1198. }
  1199. (void)(*env)->close(*env, 0);
  1200. *env = NULL;
  1201. }
  1202. return (result);
  1203. }
  1204. /*
  1205.  * bdb_DbOpen --
  1206.  * Implements the "db_create/db_open" command.
  1207.  * There are many, many options to the open command.
  1208.  * Here is the general flow:
  1209.  *
  1210.  * 0.  Preparse args to determine if we have -env.
  1211.  * 1.  Call db_create to create the db handle.
  1212.  * 2.  Parse args tracking options.
  1213.  * 3.  Make any pre-open setup calls necessary.
  1214.  * 4.  Call DB->open to open the database.
  1215.  * 5.  Return db widget handle to user.
  1216.  */
  1217. static int
  1218. bdb_DbOpen(interp, objc, objv, ip, dbp)
  1219. Tcl_Interp *interp; /* Interpreter */
  1220. int objc; /* How many arguments? */
  1221. Tcl_Obj *CONST objv[]; /* The argument objects */
  1222. DBTCL_INFO *ip; /* Our internal info */
  1223. DB **dbp; /* DB handle */
  1224. {
  1225. static char *bdbenvopen[] = {
  1226. "-env", NULL
  1227. };
  1228. enum bdbenvopen {
  1229. TCL_DB_ENV0
  1230. };
  1231. static char *bdbopen[] = {
  1232. #if CONFIG_TEST
  1233. "-btcompare",
  1234. "-dirty",
  1235. "-dupcompare",
  1236. "-hashproc",
  1237. "-lorder",
  1238. "-minkey",
  1239. "-nommap",
  1240. "-revsplitoff",
  1241. "-test",
  1242. #endif
  1243. "-auto_commit",
  1244. "-btree",
  1245. "-cachesize",
  1246. "-chksum",
  1247. "-create",
  1248. "-delim",
  1249. "-dup",
  1250. "-dupsort",
  1251. "-encrypt",
  1252. "-encryptaes",
  1253. "-encryptany",
  1254. "-env",
  1255. "-errfile",
  1256. "-errpfx",
  1257. "-excl",
  1258. "-extent",
  1259. "-ffactor",
  1260. "-hash",
  1261. "-len",
  1262. "-mode",
  1263. "-nelem",
  1264. "-pad",
  1265. "-pagesize",
  1266. "-queue",
  1267. "-rdonly",
  1268. "-recno",
  1269. "-recnum",
  1270. "-renumber",
  1271. "-snapshot",
  1272. "-source",
  1273. "-truncate",
  1274. "-txn",
  1275. "-unknown",
  1276. "--",
  1277. NULL
  1278. };
  1279. enum bdbopen {
  1280. #if CONFIG_TEST
  1281. TCL_DB_BTCOMPARE,
  1282. TCL_DB_DIRTY,
  1283. TCL_DB_DUPCOMPARE,
  1284. TCL_DB_HASHPROC,
  1285. TCL_DB_LORDER,
  1286. TCL_DB_MINKEY,
  1287. TCL_DB_NOMMAP,
  1288. TCL_DB_REVSPLIT,
  1289. TCL_DB_TEST,
  1290. #endif
  1291. TCL_DB_AUTO_COMMIT,
  1292. TCL_DB_BTREE,
  1293. TCL_DB_CACHESIZE,
  1294. TCL_DB_CHKSUM,
  1295. TCL_DB_CREATE,
  1296. TCL_DB_DELIM,
  1297. TCL_DB_DUP,
  1298. TCL_DB_DUPSORT,
  1299. TCL_DB_ENCRYPT,
  1300. TCL_DB_ENCRYPT_AES,
  1301. TCL_DB_ENCRYPT_ANY,
  1302. TCL_DB_ENV,
  1303. TCL_DB_ERRFILE,
  1304. TCL_DB_ERRPFX,
  1305. TCL_DB_EXCL,
  1306. TCL_DB_EXTENT,
  1307. TCL_DB_FFACTOR,
  1308. TCL_DB_HASH,
  1309. TCL_DB_LEN,
  1310. TCL_DB_MODE,
  1311. TCL_DB_NELEM,
  1312. TCL_DB_PAD,
  1313. TCL_DB_PAGESIZE,
  1314. TCL_DB_QUEUE,
  1315. TCL_DB_RDONLY,
  1316. TCL_DB_RECNO,
  1317. TCL_DB_RECNUM,
  1318. TCL_DB_RENUMBER,
  1319. TCL_DB_SNAPSHOT,
  1320. TCL_DB_SOURCE,
  1321. TCL_DB_TRUNCATE,
  1322. TCL_DB_TXN,
  1323. TCL_DB_UNKNOWN,
  1324. TCL_DB_ENDARG
  1325. };
  1326. DBTCL_INFO *envip, *errip;
  1327. DB_TXN *txn;
  1328. DBTYPE type;
  1329. DB_ENV *envp;
  1330. Tcl_Obj **myobjv;
  1331. u_int32_t gbytes, bytes, ncaches, open_flags, uintarg;
  1332. int endarg, i, intarg, mode, myobjc;
  1333. int optindex, result, ret, set_err, set_flags, set_pfx, subdblen;
  1334. u_char *subdbtmp;
  1335. char *arg, *db, *passwd, *subdb, msg[MSG_SIZE];
  1336. type = DB_UNKNOWN;
  1337. endarg = mode = set_err = set_flags = set_pfx = 0;
  1338. result = TCL_OK;
  1339. subdbtmp = NULL;
  1340. db = subdb = NULL;
  1341. /*
  1342.  * XXX
  1343.  * If/when our Tcl interface becomes thread-safe, we should enable
  1344.  * DB_THREAD here in all cases.  See comment in bdb_EnvOpen().
  1345.  * For now, just turn it on when testing so that we exercise
  1346.  * MUTEX_THREAD_LOCK cases.
  1347.  */
  1348. open_flags =
  1349. #ifdef TEST_THREAD
  1350.     DB_THREAD;
  1351. #else
  1352.     0;
  1353. #endif
  1354. envp = NULL;
  1355. txn = NULL;
  1356. if (objc < 2) {
  1357. Tcl_WrongNumArgs(interp, 2, objv, "?args?");
  1358. return (TCL_ERROR);
  1359. }
  1360. /*
  1361.  * We must first parse for the environment flag, since that
  1362.  * is needed for db_create.  Then create the db handle.
  1363.  */
  1364. i = 2;
  1365. while (i < objc) {
  1366. if (Tcl_GetIndexFromObj(interp, objv[i++], bdbenvopen,
  1367.     "option", TCL_EXACT, &optindex) != TCL_OK) {
  1368. /*
  1369.  * Reset the result so we don't get
  1370.  * an errant error message if there is another error.
  1371.  */
  1372. Tcl_ResetResult(interp);
  1373. continue;
  1374. }
  1375. switch ((enum bdbenvopen)optindex) {
  1376. case TCL_DB_ENV0:
  1377. arg = Tcl_GetStringFromObj(objv[i], NULL);
  1378. envp = NAME_TO_ENV(arg);
  1379. if (envp == NULL) {
  1380. Tcl_SetResult(interp,
  1381.     "db open: illegal environment", TCL_STATIC);
  1382. return (TCL_ERROR);
  1383. }
  1384. }
  1385. break;
  1386. }
  1387. /*
  1388.  * Create the db handle before parsing the args
  1389.  * since we'll be modifying the database options as we parse.
  1390.  */
  1391. ret = db_create(dbp, envp, 0);
  1392. if (ret)
  1393. return (_ReturnSetup(interp, ret, DB_RETOK_STD(ret),
  1394.     "db_create"));
  1395. /* Hang our info pointer on the DB handle, so we can do callbacks. */
  1396. (*dbp)->api_internal = ip;
  1397. /*
  1398.  * XXX Remove restriction when err stuff is not tied to env.
  1399.  *
  1400.  * The DB->set_err* functions actually overwrite in the
  1401.  * environment.  So, if we are explicitly using an env,
  1402.  * don't overwrite what we have already set up.  If we are
  1403.  * not using one, then we set up since we get a private
  1404.  * default env.
  1405.  */
  1406. /* XXX  - remove this conditional if/when err is not tied to env */
  1407. if (envp == NULL) {
  1408. (*dbp)->set_errpfx((*dbp), ip->i_name);
  1409. (*dbp)->set_errcall((*dbp), _ErrorFunc);
  1410. }
  1411. envip = _PtrToInfo(envp); /* XXX */
  1412. /*
  1413.  * If we are using an env, we keep track of err info in the env's ip.
  1414.  * Otherwise use the DB's ip.
  1415.  */
  1416. if (envip)
  1417. errip = envip;
  1418. else
  1419. errip = ip;
  1420. /*
  1421.  * Get the option name index from the object based on the args
  1422.  * defined above.
  1423.  */
  1424. i = 2;
  1425. while (i < objc) {
  1426. Tcl_ResetResult(interp);
  1427. if (Tcl_GetIndexFromObj(interp, objv[i], bdbopen, "option",
  1428.     TCL_EXACT, &optindex) != TCL_OK) {
  1429. arg = Tcl_GetStringFromObj(objv[i], NULL);
  1430. if (arg[0] == '-') {
  1431. result = IS_HELP(objv[i]);
  1432. goto error;
  1433. } else
  1434. Tcl_ResetResult(interp);
  1435. break;
  1436. }
  1437. i++;
  1438. switch ((enum bdbopen)optindex) {
  1439. #if CONFIG_TEST
  1440. case TCL_DB_BTCOMPARE:
  1441. if (i >= objc) {
  1442. Tcl_WrongNumArgs(interp, 2, objv,
  1443.     "-btcompare compareproc");
  1444. result = TCL_ERROR;
  1445. break;
  1446. }
  1447. /*
  1448.  * Store the object containing the procedure name.
  1449.  * We don't need to crack it out now--we'll want
  1450.  * to bundle it up to pass into Tcl_EvalObjv anyway.
  1451.  * Tcl's object refcounting will--I hope--take care
  1452.  * of the memory management here.
  1453.  */
  1454. ip->i_btcompare = objv[i++];
  1455. Tcl_IncrRefCount(ip->i_btcompare);
  1456. _debug_check();
  1457. ret = (*dbp)->set_bt_compare(*dbp, tcl_bt_compare);
  1458. result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
  1459.     "set_bt_compare");
  1460. break;
  1461. case TCL_DB_DIRTY:
  1462. open_flags |= DB_DIRTY_READ;
  1463. break;
  1464. case TCL_DB_DUPCOMPARE:
  1465. if (i >= objc) {
  1466. Tcl_WrongNumArgs(interp, 2, objv,
  1467.     "-dupcompare compareproc");
  1468. result = TCL_ERROR;
  1469. break;
  1470. }
  1471. /*
  1472.  * Store the object containing the procedure name.
  1473.  * See TCL_DB_BTCOMPARE.
  1474.  */
  1475. ip->i_dupcompare = objv[i++];
  1476. Tcl_IncrRefCount(ip->i_dupcompare);
  1477. _debug_check();
  1478. ret = (*dbp)->set_dup_compare(*dbp, tcl_dup_compare);
  1479. result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
  1480.     "set_dup_compare");
  1481. break;
  1482. case TCL_DB_HASHPROC:
  1483. if (i >= objc) {
  1484. Tcl_WrongNumArgs(interp, 2, objv,
  1485.     "-hashproc hashproc");
  1486. result = TCL_ERROR;
  1487. break;
  1488. }
  1489. /*
  1490.  * Store the object containing the procedure name.
  1491.  * See TCL_DB_BTCOMPARE.
  1492.  */
  1493. ip->i_hashproc = objv[i++];
  1494. Tcl_IncrRefCount(ip->i_hashproc);
  1495. _debug_check();
  1496. ret = (*dbp)->set_h_hash(*dbp, tcl_h_hash);
  1497. result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
  1498.     "set_h_hash");
  1499. break;
  1500. case TCL_DB_LORDER:
  1501. if (i >= objc) {
  1502. Tcl_WrongNumArgs(interp, 2, objv,
  1503.     "-lorder 1234|4321");
  1504. result = TCL_ERROR;
  1505. break;
  1506. }
  1507. result = _GetUInt32(interp, objv[i++], &uintarg);
  1508. if (result == TCL_OK) {
  1509. _debug_check();
  1510. ret = (*dbp)->set_lorder(*dbp, uintarg);
  1511. result = _ReturnSetup(interp, ret,
  1512.     DB_RETOK_STD(ret), "set_lorder");
  1513. }
  1514. break;
  1515. case TCL_DB_MINKEY:
  1516. if (i >= objc) {
  1517. Tcl_WrongNumArgs(interp, 2, objv,
  1518.     "-minkey minkey");
  1519. result = TCL_ERROR;
  1520. break;
  1521. }
  1522. result = _GetUInt32(interp, objv[i++], &uintarg);
  1523. if (result == TCL_OK) {
  1524. _debug_check();
  1525. ret = (*dbp)->set_bt_minkey(*dbp, uintarg);
  1526. result = _ReturnSetup(interp, ret,
  1527.     DB_RETOK_STD(ret), "set_bt_minkey");
  1528. }
  1529. break;
  1530. case TCL_DB_NOMMAP:
  1531. open_flags |= DB_NOMMAP;
  1532. break;
  1533. case TCL_DB_REVSPLIT:
  1534. set_flags |= DB_REVSPLITOFF;
  1535. break;
  1536. case TCL_DB_TEST:
  1537. (*dbp)->set_h_hash(*dbp, __ham_test);
  1538. break;
  1539. #endif
  1540. case TCL_DB_AUTO_COMMIT:
  1541. open_flags |= DB_AUTO_COMMIT;
  1542. break;
  1543. case TCL_DB_ENV:
  1544. /*
  1545.  * Already parsed this, skip it and the env pointer.
  1546.  */
  1547. i++;
  1548. continue;
  1549. case TCL_DB_TXN:
  1550. if (i > (objc - 1)) {
  1551. Tcl_WrongNumArgs(interp, 2, objv, "?-txn id?");
  1552. result = TCL_ERROR;
  1553. break;
  1554. }
  1555. arg = Tcl_GetStringFromObj(objv[i++], NULL);
  1556. txn = NAME_TO_TXN(arg);
  1557. if (txn == NULL) {
  1558. snprintf(msg, MSG_SIZE,
  1559.     "Put: Invalid txn: %sn", arg);
  1560. Tcl_SetResult(interp, msg, TCL_VOLATILE);
  1561. result = TCL_ERROR;
  1562. }
  1563. break;
  1564. case TCL_DB_BTREE:
  1565. if (type != DB_UNKNOWN) {
  1566. Tcl_SetResult(interp,
  1567.     "Too many DB types specified", TCL_STATIC);
  1568. result = TCL_ERROR;
  1569. goto error;
  1570. }
  1571. type = DB_BTREE;
  1572. break;
  1573. case TCL_DB_HASH:
  1574. if (type != DB_UNKNOWN) {
  1575. Tcl_SetResult(interp,
  1576.     "Too many DB types specified", TCL_STATIC);
  1577. result = TCL_ERROR;
  1578. goto error;
  1579. }
  1580. type = DB_HASH;
  1581. break;
  1582. case TCL_DB_RECNO:
  1583. if (type != DB_UNKNOWN) {
  1584. Tcl_SetResult(interp,
  1585.     "Too many DB types specified", TCL_STATIC);
  1586. result = TCL_ERROR;
  1587. goto error;
  1588. }
  1589. type = DB_RECNO;
  1590. break;
  1591. case TCL_DB_QUEUE:
  1592. if (type != DB_UNKNOWN) {
  1593. Tcl_SetResult(interp,
  1594.     "Too many DB types specified", TCL_STATIC);
  1595. result = TCL_ERROR;
  1596. goto error;
  1597. }
  1598. type = DB_QUEUE;
  1599. break;
  1600. case TCL_DB_UNKNOWN:
  1601. if (type != DB_UNKNOWN) {
  1602. Tcl_SetResult(interp,
  1603.     "Too many DB types specified", TCL_STATIC);
  1604. result = TCL_ERROR;
  1605. goto error;
  1606. }
  1607. break;
  1608. case TCL_DB_CREATE:
  1609. open_flags |= DB_CREATE;
  1610. break;
  1611. case TCL_DB_EXCL:
  1612. open_flags |= DB_EXCL;
  1613. break;
  1614. case TCL_DB_RDONLY:
  1615. open_flags |= DB_RDONLY;
  1616. break;
  1617. case TCL_DB_TRUNCATE:
  1618. open_flags |= DB_TRUNCATE;
  1619. break;
  1620. case TCL_DB_MODE:
  1621. if (i >= objc) {
  1622. Tcl_WrongNumArgs(interp, 2, objv,
  1623.     "?-mode mode?");
  1624. result = TCL_ERROR;
  1625. break;
  1626. }
  1627. /*
  1628.  * Don't need to check result here because
  1629.  * if TCL_ERROR, the error message is already
  1630.  * set up, and we'll bail out below.  If ok,
  1631.  * the mode is set and we go on.
  1632.  */
  1633. result = Tcl_GetIntFromObj(interp, objv[i++], &mode);
  1634. break;
  1635. case TCL_DB_DUP:
  1636. set_flags |= DB_DUP;
  1637. break;
  1638. case TCL_DB_DUPSORT:
  1639. set_flags |= DB_DUPSORT;
  1640. break;
  1641. case TCL_DB_RECNUM:
  1642. set_flags |= DB_RECNUM;
  1643. break;
  1644. case TCL_DB_RENUMBER:
  1645. set_flags |= DB_RENUMBER;
  1646. break;
  1647. case TCL_DB_SNAPSHOT:
  1648. set_flags |= DB_SNAPSHOT;
  1649. break;
  1650. case TCL_DB_CHKSUM:
  1651. set_flags |= DB_CHKSUM_SHA1;
  1652. break;
  1653. case TCL_DB_ENCRYPT:
  1654. set_flags |= DB_ENCRYPT;
  1655. break;
  1656. case TCL_DB_ENCRYPT_AES:
  1657. /* Make sure we have an arg to check against! */
  1658. if (i >= objc) {
  1659. Tcl_WrongNumArgs(interp, 2, objv,
  1660.     "?-encryptaes passwd?");
  1661. result = TCL_ERROR;
  1662. break;
  1663. }
  1664. passwd = Tcl_GetStringFromObj(objv[i++], NULL);
  1665. _debug_check();
  1666. ret = (*dbp)->set_encrypt(*dbp, passwd, DB_ENCRYPT_AES);
  1667. result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
  1668.     "set_encrypt");
  1669. break;
  1670. case TCL_DB_ENCRYPT_ANY:
  1671. /* Make sure we have an arg to check against! */
  1672. if (i >= objc) {
  1673. Tcl_WrongNumArgs(interp, 2, objv,
  1674.     "?-encryptany passwd?");
  1675. result = TCL_ERROR;
  1676. break;
  1677. }
  1678. passwd = Tcl_GetStringFromObj(objv[i++], NULL);
  1679. _debug_check();
  1680. ret = (*dbp)->set_encrypt(*dbp, passwd, 0);
  1681. result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
  1682.     "set_encrypt");
  1683. break;
  1684. case TCL_DB_FFACTOR:
  1685. if (i >= objc) {
  1686. Tcl_WrongNumArgs(interp, 2, objv,
  1687.     "-ffactor density");
  1688. result = TCL_ERROR;
  1689. break;
  1690. }
  1691. result = _GetUInt32(interp, objv[i++], &uintarg);
  1692. if (result == TCL_OK) {
  1693. _debug_check();
  1694. ret = (*dbp)->set_h_ffactor(*dbp, uintarg);
  1695. result = _ReturnSetup(interp, ret,
  1696.     DB_RETOK_STD(ret), "set_h_ffactor");
  1697. }
  1698. break;
  1699. case TCL_DB_NELEM:
  1700. if (i >= objc) {
  1701. Tcl_WrongNumArgs(interp, 2, objv,
  1702.     "-nelem nelem");
  1703. result = TCL_ERROR;
  1704. break;
  1705. }
  1706. result = _GetUInt32(interp, objv[i++], &uintarg);
  1707. if (result == TCL_OK) {
  1708. _debug_check();
  1709. ret = (*dbp)->set_h_nelem(*dbp, uintarg);
  1710. result = _ReturnSetup(interp, ret,
  1711.     DB_RETOK_STD(ret), "set_h_nelem");
  1712. }
  1713. break;
  1714. case TCL_DB_DELIM:
  1715. if (i >= objc) {
  1716. Tcl_WrongNumArgs(interp, 2, objv,
  1717.     "-delim delim");
  1718. result = TCL_ERROR;
  1719. break;
  1720. }
  1721. result = Tcl_GetIntFromObj(interp, objv[i++], &intarg);
  1722. if (result == TCL_OK) {
  1723. _debug_check();
  1724. ret = (*dbp)->set_re_delim(*dbp, intarg);
  1725. result = _ReturnSetup(interp, ret,
  1726.     DB_RETOK_STD(ret), "set_re_delim");
  1727. }
  1728. break;
  1729. case TCL_DB_LEN:
  1730. if (i >= objc) {
  1731. Tcl_WrongNumArgs(interp, 2, objv,
  1732.     "-len length");
  1733. result = TCL_ERROR;
  1734. break;
  1735. }
  1736. result = _GetUInt32(interp, objv[i++], &uintarg);
  1737. if (result == TCL_OK) {
  1738. _debug_check();
  1739. ret = (*dbp)->set_re_len(*dbp, uintarg);
  1740. result = _ReturnSetup(interp, ret,
  1741.     DB_RETOK_STD(ret), "set_re_len");
  1742. }
  1743. break;
  1744. case TCL_DB_PAD:
  1745. if (i >= objc) {
  1746. Tcl_WrongNumArgs(interp, 2, objv,
  1747.     "-pad pad");
  1748. result = TCL_ERROR;
  1749. break;
  1750. }
  1751. result = Tcl_GetIntFromObj(interp, objv[i++], &intarg);
  1752. if (result == TCL_OK) {
  1753. _debug_check();
  1754. ret = (*dbp)->set_re_pad(*dbp, intarg);
  1755. result = _ReturnSetup(interp, ret,
  1756.     DB_RETOK_STD(ret), "set_re_pad");
  1757. }
  1758. break;
  1759. case TCL_DB_SOURCE:
  1760. if (i >= objc) {
  1761. Tcl_WrongNumArgs(interp, 2, objv,
  1762.     "-source file");
  1763. result = TCL_ERROR;
  1764. break;
  1765. }
  1766. arg = Tcl_GetStringFromObj(objv[i++], NULL);
  1767. _debug_check();
  1768. ret = (*dbp)->set_re_source(*dbp, arg);
  1769. result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
  1770.     "set_re_source");
  1771. break;
  1772. case TCL_DB_EXTENT:
  1773. if (i >= objc) {
  1774. Tcl_WrongNumArgs(interp, 2, objv,
  1775.     "-extent size");
  1776. result = TCL_ERROR;
  1777. break;
  1778. }
  1779. result = _GetUInt32(interp, objv[i++], &uintarg);
  1780. if (result == TCL_OK) {
  1781. _debug_check();
  1782. ret = (*dbp)->set_q_extentsize(*dbp, uintarg);
  1783. result = _ReturnSetup(interp, ret,
  1784.     DB_RETOK_STD(ret), "set_q_extentsize");
  1785. }
  1786. break;
  1787. case TCL_DB_CACHESIZE:
  1788. result = Tcl_ListObjGetElements(interp, objv[i++],
  1789.     &myobjc, &myobjv);
  1790. if (result != TCL_OK)
  1791. break;
  1792. if (myobjc != 3) {
  1793. Tcl_WrongNumArgs(interp, 2, objv,
  1794.     "?-cachesize {gbytes bytes ncaches}?");
  1795. result = TCL_ERROR;
  1796. break;
  1797. }
  1798. result = _GetUInt32(interp, myobjv[0], &gbytes);
  1799. if (result != TCL_OK)
  1800. break;
  1801. result = _GetUInt32(interp, myobjv[1], &bytes);
  1802. if (result != TCL_OK)
  1803. break;
  1804. result = _GetUInt32(interp, myobjv[2], &ncaches);
  1805. if (result != TCL_OK)
  1806. break;
  1807. _debug_check();
  1808. ret = (*dbp)->set_cachesize(*dbp, gbytes, bytes,
  1809.     ncaches);
  1810. result = _ReturnSetup(interp, ret,
  1811.     DB_RETOK_STD(ret), "set_cachesize");
  1812. break;
  1813. case TCL_DB_PAGESIZE:
  1814. if (i >= objc) {
  1815. Tcl_WrongNumArgs(interp, 2, objv,
  1816.     "?-pagesize size?");
  1817. result = TCL_ERROR;
  1818. break;
  1819. }
  1820. result = Tcl_GetIntFromObj(interp, objv[i++], &intarg);
  1821. if (result == TCL_OK) {
  1822. _debug_check();
  1823. ret = (*dbp)->set_pagesize(*dbp,
  1824.     (size_t)intarg);
  1825. result = _ReturnSetup(interp, ret,
  1826.     DB_RETOK_STD(ret), "set pagesize");
  1827. }
  1828. break;
  1829. case TCL_DB_ERRFILE:
  1830. if (i >= objc) {
  1831. Tcl_WrongNumArgs(interp, 2, objv,
  1832.     "-errfile file");
  1833. result = TCL_ERROR;
  1834. break;
  1835. }
  1836. arg = Tcl_GetStringFromObj(objv[i++], NULL);
  1837. /*
  1838.  * If the user already set one, close it.
  1839.  */
  1840. if (errip->i_err != NULL)
  1841. fclose(errip->i_err);
  1842. errip->i_err = fopen(arg, "a");
  1843. if (errip->i_err != NULL) {
  1844. _debug_check();
  1845. (*dbp)->set_errfile(*dbp, errip->i_err);
  1846. set_err = 1;
  1847. }
  1848. break;
  1849. case TCL_DB_ERRPFX:
  1850. if (i >= objc) {
  1851. Tcl_WrongNumArgs(interp, 2, objv,
  1852.     "-errpfx prefix");
  1853. result = TCL_ERROR;
  1854. break;
  1855. }
  1856. arg = Tcl_GetStringFromObj(objv[i++], NULL);
  1857. /*
  1858.  * If the user already set one, free it.
  1859.  */
  1860. if (errip->i_errpfx != NULL)
  1861. __os_free(NULL, errip->i_errpfx);
  1862. if ((ret = __os_strdup((*dbp)->dbenv,
  1863.     arg, &errip->i_errpfx)) != 0) {
  1864. result = _ReturnSetup(interp, ret,
  1865.     DB_RETOK_STD(ret), "__os_strdup");
  1866. break;
  1867. }
  1868. if (errip->i_errpfx != NULL) {
  1869. _debug_check();
  1870. (*dbp)->set_errpfx(*dbp, errip->i_errpfx);
  1871. set_pfx = 1;
  1872. }
  1873. break;
  1874. case TCL_DB_ENDARG:
  1875. endarg = 1;
  1876. break;
  1877. } /* switch */
  1878. /*
  1879.  * If, at any time, parsing the args we get an error,
  1880.  * bail out and return.
  1881.  */
  1882. if (result != TCL_OK)
  1883. goto error;
  1884. if (endarg)
  1885. break;
  1886. }
  1887. if (result != TCL_OK)
  1888. goto error;
  1889. /*
  1890.  * Any args we have left, (better be 0, 1 or 2 left) are
  1891.  * file names.  If we have 0, then an in-memory db.  If
  1892.  * there is 1, a db name, if 2 a db and subdb name.
  1893.  */
  1894. if (i != objc) {
  1895. /*
  1896.  * Dbs must be NULL terminated file names, but subdbs can
  1897.  * be anything.  Use Strings for the db name and byte
  1898.  * arrays for the subdb.
  1899.  */
  1900. db = Tcl_GetStringFromObj(objv[i++], NULL);
  1901. if (i != objc) {
  1902. subdbtmp =
  1903.     Tcl_GetByteArrayFromObj(objv[i++], &subdblen);
  1904. if ((ret = __os_malloc(envp,
  1905.    subdblen + 1, &subdb)) != 0) {
  1906. Tcl_SetResult(interp, db_strerror(ret),
  1907.     TCL_STATIC);
  1908. return (0);
  1909. }
  1910. memcpy(subdb, subdbtmp, subdblen);
  1911. subdb[subdblen] = '';
  1912. }
  1913. }
  1914. if (set_flags) {
  1915. ret = (*dbp)->set_flags(*dbp, set_flags);
  1916. result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
  1917.     "set_flags");
  1918. if (result == TCL_ERROR)
  1919. goto error;
  1920. /*
  1921.  * If we are successful, clear the result so that the
  1922.  * return from set_flags isn't part of the result.
  1923.  */
  1924. Tcl_ResetResult(interp);
  1925. }
  1926. /*
  1927.  * When we get here, we have already parsed all of our args and made
  1928.  * all our calls to set up the database.  Everything is okay so far,
  1929.  * no errors, if we get here.
  1930.  */
  1931. _debug_check();
  1932. /* Open the database. */
  1933. ret = (*dbp)->open(*dbp, txn, db, subdb, type, open_flags, mode);
  1934. result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "db open");
  1935. error:
  1936. if (subdb)
  1937. __os_free(envp, subdb);
  1938. if (result == TCL_ERROR) {
  1939. (void)(*dbp)->close(*dbp, 0);
  1940. /*
  1941.  * If we opened and set up the error file in the environment
  1942.  * on this open, but we failed for some other reason, clean
  1943.  * up and close the file.
  1944.  *
  1945.  * XXX when err stuff isn't tied to env, change to use ip,
  1946.  * instead of envip.  Also, set_err is irrelevant when that
  1947.  * happens.  It will just read:
  1948.  * if (ip->i_err)
  1949.  * fclose(ip->i_err);
  1950.  */
  1951. if (set_err && errip && errip->i_err != NULL) {
  1952. fclose(errip->i_err);
  1953. errip->i_err = NULL;
  1954. }
  1955. if (set_pfx && errip && errip->i_errpfx != NULL) {
  1956. __os_free(envp, errip->i_errpfx);
  1957. errip->i_errpfx = NULL;
  1958. }
  1959. *dbp = NULL;
  1960. }
  1961. return (result);
  1962. }
  1963. /*
  1964.  * bdb_DbRemove --
  1965.  * Implements the DB_ENV->remove and DB->remove command.
  1966.  */
  1967. static int
  1968. bdb_DbRemove(interp, objc, objv)
  1969. Tcl_Interp *interp; /* Interpreter */
  1970. int objc; /* How many arguments? */
  1971. Tcl_Obj *CONST objv[]; /* The argument objects */
  1972. {
  1973. static char *bdbrem[] = {
  1974. "-auto_commit",
  1975. "-encrypt",
  1976. "-encryptaes",
  1977. "-encryptany",
  1978. "-env",
  1979. "-txn",
  1980. "--",
  1981. NULL
  1982. };
  1983. enum bdbrem {
  1984. TCL_DBREM_AUTOCOMMIT,
  1985. TCL_DBREM_ENCRYPT,
  1986. TCL_DBREM_ENCRYPT_AES,
  1987. TCL_DBREM_ENCRYPT_ANY,
  1988. TCL_DBREM_ENV,
  1989. TCL_DBREM_TXN,
  1990. TCL_DBREM_ENDARG
  1991. };
  1992. DB *dbp;
  1993. DB_ENV *envp;
  1994. DB_TXN *txn;
  1995. int endarg, i, optindex, result, ret, subdblen;
  1996. u_int32_t enc_flag, iflags, set_flags;
  1997. u_char *subdbtmp;
  1998. char *arg, *db, msg[MSG_SIZE], *passwd, *subdb;
  1999. db = subdb = NULL;
  2000. dbp = NULL;
  2001. endarg = 0;
  2002. envp = NULL;
  2003. iflags = enc_flag = set_flags = 0;
  2004. passwd = NULL;
  2005. result = TCL_OK;
  2006. subdbtmp = NULL;
  2007. txn = NULL;
  2008. if (objc < 2) {
  2009. Tcl_WrongNumArgs(interp, 2, objv, "?args? filename ?database?");
  2010. return (TCL_ERROR);
  2011. }
  2012. /*
  2013.  * We must first parse for the environment flag, since that
  2014.  * is needed for db_create.  Then create the db handle.
  2015.  */
  2016. i = 2;
  2017. while (i < objc) {
  2018. if (Tcl_GetIndexFromObj(interp, objv[i], bdbrem,
  2019.     "option", TCL_EXACT, &optindex) != TCL_OK) {
  2020. arg = Tcl_GetStringFromObj(objv[i], NULL);
  2021. if (arg[0] == '-') {
  2022. result = IS_HELP(objv[i]);
  2023. goto error;
  2024. } else
  2025. Tcl_ResetResult(interp);
  2026. break;
  2027. }
  2028. i++;
  2029. switch ((enum bdbrem)optindex) {
  2030. case TCL_DBREM_AUTOCOMMIT:
  2031. iflags |= DB_AUTO_COMMIT;
  2032. _debug_check();
  2033. break;
  2034. case TCL_DBREM_ENCRYPT:
  2035. set_flags |= DB_ENCRYPT;
  2036. _debug_check();
  2037. break;
  2038. case TCL_DBREM_ENCRYPT_AES:
  2039. /* Make sure we have an arg to check against! */
  2040. if (i >= objc) {
  2041. Tcl_WrongNumArgs(interp, 2, objv,
  2042.     "?-encryptaes passwd?");
  2043. result = TCL_ERROR;
  2044. break;
  2045. }
  2046. passwd = Tcl_GetStringFromObj(objv[i++], NULL);
  2047. enc_flag = DB_ENCRYPT_AES;
  2048. break;
  2049. case TCL_DBREM_ENCRYPT_ANY:
  2050. /* Make sure we have an arg to check against! */
  2051. if (i >= objc) {
  2052. Tcl_WrongNumArgs(interp, 2, objv,
  2053.     "?-encryptany passwd?");
  2054. result = TCL_ERROR;
  2055. break;
  2056. }
  2057. passwd = Tcl_GetStringFromObj(objv[i++], NULL);
  2058. enc_flag = 0;
  2059. break;
  2060. case TCL_DBREM_ENV:
  2061. arg = Tcl_GetStringFromObj(objv[i++], NULL);
  2062. envp = NAME_TO_ENV(arg);
  2063. if (envp == NULL) {
  2064. Tcl_SetResult(interp,
  2065.     "db remove: illegal environment",
  2066.     TCL_STATIC);
  2067. return (TCL_ERROR);
  2068. }
  2069. break;
  2070. case TCL_DBREM_ENDARG:
  2071. endarg = 1;
  2072. break;
  2073. case TCL_DBREM_TXN:
  2074. if (i >= objc) {
  2075. Tcl_WrongNumArgs(interp, 2, objv, "?-txn id?");
  2076. result = TCL_ERROR;
  2077. break;
  2078. }
  2079. arg = Tcl_GetStringFromObj(objv[i++], NULL);
  2080. txn = NAME_TO_TXN(arg);
  2081. if (txn == NULL) {
  2082. snprintf(msg, MSG_SIZE,
  2083.     "Put: Invalid txn: %sn", arg);
  2084. Tcl_SetResult(interp, msg, TCL_VOLATILE);
  2085. result = TCL_ERROR;
  2086. }
  2087. break;
  2088. }
  2089. /*
  2090.  * If, at any time, parsing the args we get an error,
  2091.  * bail out and return.
  2092.  */
  2093. if (result != TCL_OK)
  2094. goto error;
  2095. if (endarg)
  2096. break;
  2097. }
  2098. if (result != TCL_OK)
  2099. goto error;
  2100. /*
  2101.  * Any args we have left, (better be 1 or 2 left) are
  2102.  * file names. If there is 1, a db name, if 2 a db and subdb name.
  2103.  */
  2104. if ((i != (objc - 1)) || (i != (objc - 2))) {
  2105. /*
  2106.  * Dbs must be NULL terminated file names, but subdbs can
  2107.  * be anything.  Use Strings for the db name and byte
  2108.  * arrays for the subdb.
  2109.  */
  2110. db = Tcl_GetStringFromObj(objv[i++], NULL);
  2111. if (i != objc) {
  2112. subdbtmp =
  2113.     Tcl_GetByteArrayFromObj(objv[i++], &subdblen);
  2114. if ((ret = __os_malloc(envp, subdblen + 1,
  2115.     &subdb)) != 0) { Tcl_SetResult(interp,
  2116.     db_strerror(ret), TCL_STATIC);
  2117. return (0);
  2118. }
  2119. memcpy(subdb, subdbtmp, subdblen);
  2120. subdb[subdblen] = '';
  2121. }
  2122. } else {
  2123. Tcl_WrongNumArgs(interp, 2, objv, "?args? filename ?database?");
  2124. result = TCL_ERROR;
  2125. goto error;
  2126. }
  2127. if (envp == NULL) {
  2128. ret = db_create(&dbp, envp, 0);
  2129. if (ret) {
  2130. result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
  2131.     "db_create");
  2132. goto error;
  2133. }
  2134. if (passwd != NULL) {
  2135. ret = dbp->set_encrypt(dbp, passwd, enc_flag);
  2136. result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
  2137.     "set_encrypt");
  2138. }
  2139. if (set_flags != 0) {
  2140. ret = dbp->set_flags(dbp, set_flags);
  2141. result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
  2142.     "set_flags");
  2143. }
  2144. }
  2145. /*
  2146.  * No matter what, we NULL out dbp after this call.
  2147.  */
  2148. _debug_check();
  2149. if (dbp == NULL)
  2150. ret = envp->dbremove(envp, txn, db, subdb, iflags);
  2151. else
  2152. ret = dbp->remove(dbp, db, subdb, 0);
  2153. result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "db remove");
  2154. dbp = NULL;
  2155. error:
  2156. if (subdb)
  2157. __os_free(envp, subdb);
  2158. if (result == TCL_ERROR && dbp != NULL)
  2159. (void)dbp->close(dbp, 0);
  2160. return (result);
  2161. }
  2162. /*
  2163.  * bdb_DbRename --
  2164.  * Implements the DBENV->dbrename and DB->rename commands.
  2165.  */
  2166. static int
  2167. bdb_DbRename(interp, objc, objv)
  2168. Tcl_Interp *interp; /* Interpreter */
  2169. int objc; /* How many arguments? */
  2170. Tcl_Obj *CONST objv[]; /* The argument objects */
  2171. {
  2172. static char *bdbmv[] = {
  2173. "-auto_commit",
  2174. "-encrypt",
  2175. "-encryptaes",
  2176. "-encryptany",
  2177. "-env",
  2178. "-txn",
  2179. "--",
  2180. NULL
  2181. };
  2182. enum bdbmv {
  2183. TCL_DBMV_AUTOCOMMIT,
  2184. TCL_DBMV_ENCRYPT,
  2185. TCL_DBMV_ENCRYPT_AES,
  2186. TCL_DBMV_ENCRYPT_ANY,
  2187. TCL_DBMV_ENV,
  2188. TCL_DBMV_TXN,
  2189. TCL_DBMV_ENDARG
  2190. };
  2191. DB *dbp;
  2192. DB_ENV *envp;
  2193. DB_TXN *txn;
  2194. u_int32_t enc_flag, iflags, set_flags;
  2195. int endarg, i, newlen, optindex, result, ret, subdblen;
  2196. u_char *subdbtmp;
  2197. char *arg, *db, msg[MSG_SIZE], *newname, *passwd, *subdb;
  2198. db = newname = subdb = NULL;
  2199. dbp = NULL;
  2200. endarg = 0;
  2201. envp = NULL;
  2202. iflags = enc_flag = set_flags = 0;
  2203. passwd = NULL;
  2204. result = TCL_OK;
  2205. subdbtmp = NULL;
  2206. txn = NULL;
  2207. if (objc < 2) {
  2208. Tcl_WrongNumArgs(interp,
  2209. 3, objv, "?args? filename ?database? ?newname?");
  2210. return (TCL_ERROR);
  2211. }
  2212. /*
  2213.  * We must first parse for the environment flag, since that
  2214.  * is needed for db_create.  Then create the db handle.
  2215.  */
  2216. i = 2;
  2217. while (i < objc) {
  2218. if (Tcl_GetIndexFromObj(interp, objv[i], bdbmv,
  2219.     "option", TCL_EXACT, &optindex) != TCL_OK) {
  2220. arg = Tcl_GetStringFromObj(objv[i], NULL);
  2221. if (arg[0] == '-') {
  2222. result = IS_HELP(objv[i]);
  2223. goto error;
  2224. } else
  2225. Tcl_ResetResult(interp);
  2226. break;
  2227. }
  2228. i++;
  2229. switch ((enum bdbmv)optindex) {
  2230. case TCL_DBMV_AUTOCOMMIT:
  2231. iflags |= DB_AUTO_COMMIT;
  2232. _debug_check();
  2233. break;
  2234. case TCL_DBMV_ENCRYPT:
  2235. set_flags |= DB_ENCRYPT;
  2236. _debug_check();
  2237. break;
  2238. case TCL_DBMV_ENCRYPT_AES:
  2239. /* Make sure we have an arg to check against! */
  2240. if (i >= objc) {
  2241. Tcl_WrongNumArgs(interp, 2, objv,
  2242.     "?-encryptaes passwd?");
  2243. result = TCL_ERROR;
  2244. break;
  2245. }
  2246. passwd = Tcl_GetStringFromObj(objv[i++], NULL);
  2247. enc_flag = DB_ENCRYPT_AES;
  2248. break;
  2249. case TCL_DBMV_ENCRYPT_ANY:
  2250. /* Make sure we have an arg to check against! */
  2251. if (i >= objc) {
  2252. Tcl_WrongNumArgs(interp, 2, objv,
  2253.     "?-encryptany passwd?");
  2254. result = TCL_ERROR;
  2255. break;
  2256. }
  2257. passwd = Tcl_GetStringFromObj(objv[i++], NULL);
  2258. enc_flag = 0;
  2259. break;
  2260. case TCL_DBMV_ENV:
  2261. arg = Tcl_GetStringFromObj(objv[i++], NULL);
  2262. envp = NAME_TO_ENV(arg);
  2263. if (envp == NULL) {
  2264. Tcl_SetResult(interp,
  2265.     "db rename: illegal environment",
  2266.     TCL_STATIC);
  2267. return (TCL_ERROR);
  2268. }
  2269. break;
  2270. case TCL_DBMV_ENDARG:
  2271. endarg = 1;
  2272. break;
  2273. case TCL_DBMV_TXN:
  2274. if (i >= objc) {
  2275. Tcl_WrongNumArgs(interp, 2, objv, "?-txn id?");
  2276. result = TCL_ERROR;
  2277. break;
  2278. }
  2279. arg = Tcl_GetStringFromObj(objv[i++], NULL);
  2280. txn = NAME_TO_TXN(arg);
  2281. if (txn == NULL) {
  2282. snprintf(msg, MSG_SIZE,
  2283.     "Put: Invalid txn: %sn", arg);
  2284. Tcl_SetResult(interp, msg, TCL_VOLATILE);
  2285. result = TCL_ERROR;
  2286. }
  2287. break;
  2288. }
  2289. /*
  2290.  * If, at any time, parsing the args we get an error,
  2291.  * bail out and return.
  2292.  */
  2293. if (result != TCL_OK)
  2294. goto error;
  2295. if (endarg)
  2296. break;
  2297. }
  2298. if (result != TCL_OK)
  2299. goto error;
  2300. /*
  2301.  * Any args we have left, (better be 2 or 3 left) are
  2302.  * file names. If there is 2, a file name, if 3 a file and db name.
  2303.  */
  2304. if ((i != (objc - 2)) || (i != (objc - 3))) {
  2305. /*
  2306.  * Dbs must be NULL terminated file names, but subdbs can
  2307.  * be anything.  Use Strings for the db name and byte
  2308.  * arrays for the subdb.
  2309.  */
  2310. db = Tcl_GetStringFromObj(objv[i++], NULL);
  2311. if (i == objc - 2) {
  2312. subdbtmp =
  2313.     Tcl_GetByteArrayFromObj(objv[i++], &subdblen);
  2314. if ((ret = __os_malloc(envp, subdblen + 1,
  2315.     &subdb)) != 0) {
  2316. Tcl_SetResult(interp,
  2317.     db_strerror(ret), TCL_STATIC);
  2318. return (0);
  2319. }
  2320. memcpy(subdb, subdbtmp, subdblen);
  2321. subdb[subdblen] = '';
  2322. }
  2323. subdbtmp =
  2324.     Tcl_GetByteArrayFromObj(objv[i++], &newlen);
  2325. if ((ret = __os_malloc(envp, newlen + 1,
  2326.     &newname)) != 0) {
  2327. Tcl_SetResult(interp,
  2328.     db_strerror(ret), TCL_STATIC);
  2329. return (0);
  2330. }
  2331. memcpy(newname, subdbtmp, newlen);
  2332. newname[newlen] = '';
  2333. } else {
  2334. Tcl_WrongNumArgs(
  2335.     interp, 3, objv, "?args? filename ?database? ?newname?");
  2336. result = TCL_ERROR;
  2337. goto error;
  2338. }
  2339. if (envp == NULL) {
  2340. ret = db_create(&dbp, envp, 0);
  2341. if (ret) {
  2342. result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
  2343.     "db_create");
  2344. goto error;
  2345. }
  2346. if (passwd != NULL) {
  2347. ret = dbp->set_encrypt(dbp, passwd, enc_flag);
  2348. result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
  2349.     "set_encrypt");
  2350. }
  2351. if (set_flags != 0) {
  2352. ret = dbp->set_flags(dbp, set_flags);
  2353. result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
  2354.     "set_flags");
  2355. }
  2356. }
  2357. /*
  2358.  * No matter what, we NULL out dbp after this call.
  2359.  */
  2360. if (dbp == NULL)
  2361. ret = envp->dbrename(envp, txn, db, subdb, newname, iflags);
  2362. else
  2363. ret = dbp->rename(dbp, db, subdb, newname, 0);
  2364. result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "db rename");
  2365. dbp = NULL;
  2366. error:
  2367. if (subdb)
  2368. __os_free(envp, subdb);
  2369. if (newname)
  2370. __os_free(envp, newname);
  2371. if (result == TCL_ERROR && dbp != NULL)
  2372. (void)dbp->close(dbp, 0);
  2373. return (result);
  2374. }
  2375. #if CONFIG_TEST
  2376. /*
  2377.  * bdb_DbVerify --
  2378.  * Implements the DB->verify command.
  2379.  */
  2380. static int
  2381. bdb_DbVerify(interp, objc, objv)
  2382. Tcl_Interp *interp; /* Interpreter */
  2383. int objc; /* How many arguments? */
  2384. Tcl_Obj *CONST objv[]; /* The argument objects */
  2385. {
  2386. static char *bdbverify[] = {
  2387. "-encrypt",
  2388. "-encryptaes",
  2389. "-encryptany",
  2390. "-env",
  2391. "-errfile",
  2392. "-errpfx",
  2393. "--",
  2394. NULL
  2395. };
  2396. enum bdbvrfy {
  2397. TCL_DBVRFY_ENCRYPT,
  2398. TCL_DBVRFY_ENCRYPT_AES,
  2399. TCL_DBVRFY_ENCRYPT_ANY,
  2400. TCL_DBVRFY_ENV,
  2401. TCL_DBVRFY_ERRFILE,
  2402. TCL_DBVRFY_ERRPFX,
  2403. TCL_DBVRFY_ENDARG
  2404. };
  2405. DB_ENV *envp;
  2406. DB *dbp;
  2407. FILE *errf;
  2408. u_int32_t enc_flag, flags, set_flags;
  2409. int endarg, i, optindex, result, ret;
  2410. char *arg, *db, *errpfx, *passwd;
  2411. envp = NULL;
  2412. dbp = NULL;
  2413. passwd = NULL;
  2414. result = TCL_OK;
  2415. db = errpfx = NULL;
  2416. errf = NULL;
  2417. flags = endarg = 0;
  2418. enc_flag = set_flags = 0;
  2419. if (objc < 2) {
  2420. Tcl_WrongNumArgs(interp, 2, objv, "?args? filename");
  2421. return (TCL_ERROR);
  2422. }
  2423. /*
  2424.  * We must first parse for the environment flag, since that
  2425.  * is needed for db_create.  Then create the db handle.
  2426.  */
  2427. i = 2;
  2428. while (i < objc) {
  2429. if (Tcl_GetIndexFromObj(interp, objv[i], bdbverify,
  2430.     "option", TCL_EXACT, &optindex) != TCL_OK) {
  2431. arg = Tcl_GetStringFromObj(objv[i], NULL);
  2432. if (arg[0] == '-') {
  2433. result = IS_HELP(objv[i]);
  2434. goto error;
  2435. } else
  2436. Tcl_ResetResult(interp);
  2437. break;
  2438. }
  2439. i++;
  2440. switch ((enum bdbvrfy)optindex) {
  2441. case TCL_DBVRFY_ENCRYPT:
  2442. set_flags |= DB_ENCRYPT;
  2443. _debug_check();
  2444. break;
  2445. case TCL_DBVRFY_ENCRYPT_AES:
  2446. /* Make sure we have an arg to check against! */
  2447. if (i >= objc) {
  2448. Tcl_WrongNumArgs(interp, 2, objv,
  2449.     "?-encryptaes passwd?");
  2450. result = TCL_ERROR;
  2451. break;
  2452. }
  2453. passwd = Tcl_GetStringFromObj(objv[i++], NULL);
  2454. enc_flag = DB_ENCRYPT_AES;
  2455. break;
  2456. case TCL_DBVRFY_ENCRYPT_ANY:
  2457. /* Make sure we have an arg to check against! */
  2458. if (i >= objc) {
  2459. Tcl_WrongNumArgs(interp, 2, objv,
  2460.     "?-encryptany passwd?");
  2461. result = TCL_ERROR;
  2462. break;
  2463. }
  2464. passwd = Tcl_GetStringFromObj(objv[i++], NULL);
  2465. enc_flag = 0;
  2466. break;
  2467. case TCL_DBVRFY_ENV:
  2468. arg = Tcl_GetStringFromObj(objv[i++], NULL);
  2469. envp = NAME_TO_ENV(arg);
  2470. if (envp == NULL) {
  2471. Tcl_SetResult(interp,
  2472.     "db verify: illegal environment",
  2473.     TCL_STATIC);
  2474. result = TCL_ERROR;
  2475. break;
  2476. }
  2477. break;
  2478. case TCL_DBVRFY_ERRFILE:
  2479. if (i >= objc) {
  2480. Tcl_WrongNumArgs(interp, 2, objv,
  2481.     "-errfile file");
  2482. result = TCL_ERROR;
  2483. break;
  2484. }
  2485. arg = Tcl_GetStringFromObj(objv[i++], NULL);
  2486. /*
  2487.  * If the user already set one, close it.
  2488.  */
  2489. if (errf != NULL)
  2490. fclose(errf);
  2491. errf = fopen(arg, "a");
  2492. break;
  2493. case TCL_DBVRFY_ERRPFX:
  2494. if (i >= objc) {
  2495. Tcl_WrongNumArgs(interp, 2, objv,
  2496.     "-errpfx prefix");
  2497. result = TCL_ERROR;
  2498. break;
  2499. }
  2500. arg = Tcl_GetStringFromObj(objv[i++], NULL);
  2501. /*
  2502.  * If the user already set one, free it.
  2503.  */
  2504. if (errpfx != NULL)
  2505. __os_free(envp, errpfx);
  2506. if ((ret = __os_strdup(NULL, arg, &errpfx)) != 0) {
  2507. result = _ReturnSetup(interp, ret,
  2508.     DB_RETOK_STD(ret), "__os_strdup");
  2509. break;
  2510. }
  2511. break;
  2512. case TCL_DBVRFY_ENDARG:
  2513. endarg = 1;
  2514. break;
  2515. }
  2516. /*
  2517.  * If, at any time, parsing the args we get an error,
  2518.  * bail out and return.
  2519.  */
  2520. if (result != TCL_OK)
  2521. goto error;
  2522. if (endarg)
  2523. break;
  2524. }
  2525. if (result != TCL_OK)
  2526. goto error;
  2527. /*
  2528.  * The remaining arg is the db filename.
  2529.  */
  2530. if (i == (objc - 1))
  2531. db = Tcl_GetStringFromObj(objv[i++], NULL);
  2532. else {
  2533. Tcl_WrongNumArgs(interp, 2, objv, "?args? filename");
  2534. result = TCL_ERROR;
  2535. goto error;
  2536. }
  2537. ret = db_create(&dbp, envp, 0);
  2538. if (ret) {
  2539. result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
  2540.     "db_create");
  2541. goto error;
  2542. }
  2543. if (passwd != NULL) {
  2544. ret = dbp->set_encrypt(dbp, passwd, enc_flag);
  2545. result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
  2546.     "set_encrypt");
  2547. }
  2548. if (set_flags != 0) {
  2549. ret = dbp->set_flags(dbp, set_flags);
  2550. result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
  2551.     "set_flags");
  2552. }
  2553. if (errf != NULL)
  2554. dbp->set_errfile(dbp, errf);
  2555. if (errpfx != NULL)
  2556. dbp->set_errpfx(dbp, errpfx);
  2557. ret = dbp->verify(dbp, db, NULL, NULL, flags);
  2558. result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "db verify");
  2559. error:
  2560. if (errf != NULL)
  2561. fclose(errf);
  2562. if (errpfx != NULL)
  2563. __os_free(envp, errpfx);
  2564. if (dbp)
  2565. (void)dbp->close(dbp, 0);
  2566. return (result);
  2567. }
  2568. #endif
  2569. /*
  2570.  * bdb_Version --
  2571.  * Implements the version command.
  2572.  */
  2573. static int
  2574. bdb_Version(interp, objc, objv)
  2575. Tcl_Interp *interp; /* Interpreter */
  2576. int objc; /* How many arguments? */
  2577. Tcl_Obj *CONST objv[]; /* The argument objects */
  2578. {
  2579. static char *bdbver[] = {
  2580. "-string", NULL
  2581. };
  2582. enum bdbver {
  2583. TCL_VERSTRING
  2584. };
  2585. int i, optindex, maj, min, patch, result, string, verobjc;
  2586. char *arg, *v;
  2587. Tcl_Obj *res, *verobjv[3];
  2588. result = TCL_OK;
  2589. string = 0;
  2590. if (objc < 2) {
  2591. Tcl_WrongNumArgs(interp, 2, objv, "?args?");
  2592. return (TCL_ERROR);
  2593. }
  2594. /*
  2595.  * We must first parse for the environment flag, since that
  2596.  * is needed for db_create.  Then create the db handle.
  2597.  */
  2598. i = 2;
  2599. while (i < objc) {
  2600. if (Tcl_GetIndexFromObj(interp, objv[i], bdbver,
  2601.     "option", TCL_EXACT, &optindex) != TCL_OK) {
  2602. arg = Tcl_GetStringFromObj(objv[i], NULL);
  2603. if (arg[0] == '-') {
  2604. result = IS_HELP(objv[i]);
  2605. goto error;
  2606. } else
  2607. Tcl_ResetResult(interp);
  2608. break;
  2609. }
  2610. i++;
  2611. switch ((enum bdbver)optindex) {
  2612. case TCL_VERSTRING:
  2613. string = 1;
  2614. break;
  2615. }
  2616. /*
  2617.  * If, at any time, parsing the args we get an error,
  2618.  * bail out and return.
  2619.  */
  2620. if (result != TCL_OK)
  2621. goto error;
  2622. }
  2623. if (result != TCL_OK)
  2624. goto error;
  2625. v = db_version(&maj, &min, &patch);
  2626. if (string)
  2627. res = Tcl_NewStringObj(v, strlen(v));
  2628. else {
  2629. verobjc = 3;
  2630. verobjv[0] = Tcl_NewIntObj(maj);
  2631. verobjv[1] = Tcl_NewIntObj(min);
  2632. verobjv[2] = Tcl_NewIntObj(patch);
  2633. res = Tcl_NewListObj(verobjc, verobjv);
  2634. }
  2635. Tcl_SetObjResult(interp, res);
  2636. error:
  2637. return (result);
  2638. }
  2639. #if CONFIG_TEST
  2640. /*
  2641.  * bdb_Handles --
  2642.  * Implements the handles command.
  2643.  */
  2644. static int
  2645. bdb_Handles(interp, objc, objv)
  2646. Tcl_Interp *interp; /* Interpreter */
  2647. int objc; /* How many arguments? */
  2648. Tcl_Obj *CONST objv[]; /* The argument objects */
  2649. {
  2650. DBTCL_INFO *p;
  2651. Tcl_Obj *res, *handle;
  2652. /*
  2653.  * No args.  Error if we have some
  2654.  */
  2655. if (objc != 2) {
  2656. Tcl_WrongNumArgs(interp, 2, objv, "");
  2657. return (TCL_ERROR);
  2658. }
  2659. res = Tcl_NewListObj(0, NULL);
  2660. for (p = LIST_FIRST(&__db_infohead); p != NULL;
  2661.     p = LIST_NEXT(p, entries)) {
  2662. handle = Tcl_NewStringObj(p->i_name, strlen(p->i_name));
  2663. if (Tcl_ListObjAppendElement(interp, res, handle) != TCL_OK)
  2664. return (TCL_ERROR);
  2665. }
  2666. Tcl_SetObjResult(interp, res);
  2667. return (TCL_OK);
  2668. }
  2669. #endif
  2670. #if CONFIG_TEST
  2671. /*
  2672.  * bdb_DbUpgrade --
  2673.  * Implements the DB->upgrade command.
  2674.  */
  2675. static int
  2676. bdb_DbUpgrade(interp, objc, objv)
  2677. Tcl_Interp *interp; /* Interpreter */
  2678. int objc; /* How many arguments? */
  2679. Tcl_Obj *CONST objv[]; /* The argument objects */
  2680. {
  2681. static char *bdbupg[] = {
  2682. "-dupsort", "-env", "--", NULL
  2683. };
  2684. enum bdbupg {
  2685. TCL_DBUPG_DUPSORT,
  2686. TCL_DBUPG_ENV,
  2687. TCL_DBUPG_ENDARG
  2688. };
  2689. DB_ENV *envp;
  2690. DB *dbp;
  2691. u_int32_t flags;
  2692. int endarg, i, optindex, result, ret;
  2693. char *arg, *db;
  2694. envp = NULL;
  2695. dbp = NULL;
  2696. result = TCL_OK;
  2697. db = NULL;
  2698. flags = endarg = 0;
  2699. if (objc < 2) {
  2700. Tcl_WrongNumArgs(interp, 2, objv, "?args? filename");
  2701. return (TCL_ERROR);
  2702. }
  2703. i = 2;
  2704. while (i < objc) {
  2705. if (Tcl_GetIndexFromObj(interp, objv[i], bdbupg,
  2706.     "option", TCL_EXACT, &optindex) != TCL_OK) {
  2707. arg = Tcl_GetStringFromObj(objv[i], NULL);
  2708. if (arg[0] == '-') {
  2709. result = IS_HELP(objv[i]);
  2710. goto error;
  2711. } else
  2712. Tcl_ResetResult(interp);
  2713. break;
  2714. }
  2715. i++;
  2716. switch ((enum bdbupg)optindex) {
  2717. case TCL_DBUPG_DUPSORT:
  2718. flags |= DB_DUPSORT;
  2719. break;
  2720. case TCL_DBUPG_ENV:
  2721. arg = Tcl_GetStringFromObj(objv[i++], NULL);
  2722. envp = NAME_TO_ENV(arg);
  2723. if (envp == NULL) {
  2724. Tcl_SetResult(interp,
  2725.     "db upgrade: illegal environment",
  2726.     TCL_STATIC);
  2727. return (TCL_ERROR);
  2728. }
  2729. break;
  2730. case TCL_DBUPG_ENDARG:
  2731. endarg = 1;
  2732. break;
  2733. }
  2734. /*
  2735.  * If, at any time, parsing the args we get an error,
  2736.  * bail out and return.
  2737.  */
  2738. if (result != TCL_OK)
  2739. goto error;
  2740. if (endarg)
  2741. break;
  2742. }
  2743. if (result != TCL_OK)
  2744. goto error;
  2745. /*
  2746.  * The remaining arg is the db filename.
  2747.  */
  2748. if (i == (objc - 1))
  2749. db = Tcl_GetStringFromObj(objv[i++], NULL);
  2750. else {
  2751. Tcl_WrongNumArgs(interp, 2, objv, "?args? filename");
  2752. result = TCL_ERROR;
  2753. goto error;
  2754. }
  2755. ret = db_create(&dbp, envp, 0);
  2756. if (ret) {
  2757. result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
  2758.     "db_create");
  2759. goto error;
  2760. }
  2761. ret = dbp->upgrade(dbp, db, flags);
  2762. result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "db upgrade");
  2763. error:
  2764. if (dbp)
  2765. (void)dbp->close(dbp, 0);
  2766. return (result);
  2767. }
  2768. #endif
  2769. /*
  2770.  * tcl_bt_compare and tcl_dup_compare --
  2771.  * These two are basically identical internally, so may as well
  2772.  * share code.  The only differences are the name used in error
  2773.  * reporting and the Tcl_Obj representing their respective procs.
  2774.  */
  2775. static int
  2776. tcl_bt_compare(dbp, dbta, dbtb)
  2777. DB *dbp;
  2778. const DBT *dbta, *dbtb;
  2779. {
  2780. return (tcl_compare_callback(dbp, dbta, dbtb,
  2781.     ((DBTCL_INFO *)dbp->api_internal)->i_btcompare, "bt_compare"));
  2782. }
  2783. static int
  2784. tcl_dup_compare(dbp, dbta, dbtb)
  2785. DB *dbp;
  2786. const DBT *dbta, *dbtb;
  2787. {
  2788. return (tcl_compare_callback(dbp, dbta, dbtb,
  2789.     ((DBTCL_INFO *)dbp->api_internal)->i_dupcompare, "dup_compare"));
  2790. }
  2791. /*
  2792.  * tcl_compare_callback --
  2793.  * Tcl callback for set_bt_compare and set_dup_compare. What this
  2794.  * function does is stuff the data fields of the two DBTs into Tcl ByteArray
  2795.  * objects, then call the procedure stored in ip->i_btcompare on the two
  2796.  * objects.  Then we return that procedure's result as the comparison.
  2797.  */
  2798. static int
  2799. tcl_compare_callback(dbp, dbta, dbtb, procobj, errname)
  2800. DB *dbp;
  2801. const DBT *dbta, *dbtb;
  2802. Tcl_Obj *procobj;
  2803. char *errname;
  2804. {
  2805. DBTCL_INFO *ip;
  2806. Tcl_Interp *interp;
  2807. Tcl_Obj *a, *b, *resobj, *objv[3];
  2808. int result, cmp;
  2809. ip = (DBTCL_INFO *)dbp->api_internal;
  2810. interp = ip->i_interp;
  2811. objv[0] = procobj;
  2812. /*
  2813.  * Create two ByteArray objects, with the two data we've been passed.
  2814.  * This will involve a copy, which is unpleasantly slow, but there's
  2815.  * little we can do to avoid this (I think).
  2816.  */
  2817. a = Tcl_NewByteArrayObj(dbta->data, dbta->size);
  2818. Tcl_IncrRefCount(a);
  2819. b = Tcl_NewByteArrayObj(dbtb->data, dbtb->size);
  2820. Tcl_IncrRefCount(b);
  2821. objv[1] = a;
  2822. objv[2] = b;
  2823. result = Tcl_EvalObjv(interp, 3, objv, 0);
  2824. if (result != TCL_OK) {
  2825. /*
  2826.  * XXX
  2827.  * If this or the next Tcl call fails, we're doomed.
  2828.  * There's no way to return an error from comparison functions,
  2829.  * no way to determine what the correct sort order is, and
  2830.  * so no way to avoid corrupting the database if we proceed.
  2831.  * We could play some games stashing return values on the
  2832.  * DB handle, but it's not worth the trouble--no one with
  2833.  * any sense is going to be using this other than for testing,
  2834.  * and failure typically means that the bt_compare proc
  2835.  * had a syntax error in it or something similarly dumb.
  2836.  *
  2837.  * So, drop core.  If we're not running with diagnostic
  2838.  * mode, panic--and always return a negative number. :-)
  2839.  */
  2840. panic: __db_err(dbp->dbenv, "Tcl %s callback failed", errname);
  2841. DB_ASSERT(0);
  2842. return (__db_panic(dbp->dbenv, DB_RUNRECOVERY));
  2843. }
  2844. resobj = Tcl_GetObjResult(interp);
  2845. result = Tcl_GetIntFromObj(interp, resobj, &cmp);
  2846. if (result != TCL_OK)
  2847. goto panic;
  2848. Tcl_DecrRefCount(a);
  2849. Tcl_DecrRefCount(b);
  2850. return (cmp);
  2851. }
  2852. /*
  2853.  * tcl_h_hash --
  2854.  * Tcl callback for the hashing function.  See tcl_compare_callback--
  2855.  * this works much the same way, only we're given a buffer and a length
  2856.  * instead of two DBTs.
  2857.  */
  2858. static u_int32_t
  2859. tcl_h_hash(dbp, buf, len)
  2860. DB *dbp;
  2861. const void *buf;
  2862. u_int32_t len;
  2863. {
  2864. DBTCL_INFO *ip;
  2865. Tcl_Interp *interp;
  2866. Tcl_Obj *objv[2];
  2867. int result, hval;
  2868. ip = (DBTCL_INFO *)dbp->api_internal;
  2869. interp = ip->i_interp;
  2870. objv[0] = ip->i_hashproc;
  2871. /*
  2872.  * Create a ByteArray for the buffer.
  2873.  */
  2874. objv[1] = Tcl_NewByteArrayObj((void *)buf, len);
  2875. Tcl_IncrRefCount(objv[1]);
  2876. result = Tcl_EvalObjv(interp, 2, objv, 0);
  2877. if (result != TCL_OK) {
  2878. /*
  2879.  * XXX
  2880.  * We drop core on error.  See the comment in
  2881.  * tcl_compare_callback.
  2882.  */
  2883. panic: __db_err(dbp->dbenv, "Tcl h_hash callback failed");
  2884. DB_ASSERT(0);
  2885. return (__db_panic(dbp->dbenv, DB_RUNRECOVERY));
  2886. }
  2887. result = Tcl_GetIntFromObj(interp, Tcl_GetObjResult(interp), &hval);
  2888. if (result != TCL_OK)
  2889. goto panic;
  2890. Tcl_DecrRefCount(objv[1]);
  2891. return (hval);
  2892. }
  2893. /*
  2894.  * tcl_rep_send --
  2895.  * Replication send callback.
  2896.  */
  2897. static int
  2898. tcl_rep_send(dbenv, control, rec, eid, flags)
  2899. DB_ENV *dbenv;
  2900. const DBT *control, *rec;
  2901. int eid;
  2902. u_int32_t flags;
  2903. {
  2904. DBTCL_INFO *ip;
  2905. Tcl_Interp *interp;
  2906. Tcl_Obj *control_o, *eid_o, *origobj, *rec_o, *resobj, *objv[5];
  2907. int result, ret;
  2908. COMPQUIET(flags, 0);
  2909. ip = (DBTCL_INFO *)dbenv->app_private;
  2910. interp = ip->i_interp;
  2911. objv[0] = ip->i_rep_send;
  2912. control_o = Tcl_NewByteArrayObj(control->data, control->size);
  2913. Tcl_IncrRefCount(control_o);
  2914. rec_o = Tcl_NewByteArrayObj(rec->data, rec->size);
  2915. Tcl_IncrRefCount(rec_o);
  2916. eid_o = Tcl_NewIntObj(eid);
  2917. Tcl_IncrRefCount(eid_o);
  2918. objv[1] = control_o;
  2919. objv[2] = rec_o;
  2920. objv[3] = ip->i_rep_eid; /* From ID */
  2921. objv[4] = eid_o; /* To ID */
  2922. /*
  2923.  * We really want to return the original result to the
  2924.  * user.  So, save the result obj here, and then after
  2925.  * we've taken care of the Tcl_EvalObjv, set the result
  2926.  * back to this original result.
  2927.  */
  2928. origobj = Tcl_GetObjResult(interp);
  2929. Tcl_IncrRefCount(origobj);
  2930. result = Tcl_EvalObjv(interp, 5, objv, 0);
  2931. if (result != TCL_OK) {
  2932. /*
  2933.  * XXX
  2934.  * This probably isn't the right error behavior, but
  2935.  * this error should only happen if the Tcl callback is
  2936.  * somehow invalid, which is a fatal scripting bug.
  2937.  */
  2938. err: __db_err(dbenv, "Tcl rep_send failure");
  2939. return (EINVAL);
  2940. }
  2941. resobj = Tcl_GetObjResult(interp);
  2942. result = Tcl_GetIntFromObj(interp, resobj, &ret);
  2943. if (result != TCL_OK)
  2944. goto err;
  2945. Tcl_SetObjResult(interp, origobj);
  2946. Tcl_DecrRefCount(origobj);
  2947. Tcl_DecrRefCount(control_o);
  2948. Tcl_DecrRefCount(rec_o);
  2949. Tcl_DecrRefCount(eid_o);
  2950. return (ret);
  2951. }
  2952. #ifdef TEST_ALLOC
  2953. /*
  2954.  * tcl_db_malloc, tcl_db_realloc, tcl_db_free --
  2955.  * Tcl-local malloc, realloc, and free functions to use for user data
  2956.  * to exercise umalloc/urealloc/ufree.  Allocate the memory as a Tcl object
  2957.  * so we're sure to exacerbate and catch any shared-library issues.
  2958.  */
  2959. static void *
  2960. tcl_db_malloc(size)
  2961. size_t size;
  2962. {
  2963. Tcl_Obj *obj;
  2964. void *buf;
  2965. obj = Tcl_NewObj();
  2966. if (obj == NULL)
  2967. return (NULL);
  2968. Tcl_IncrRefCount(obj);
  2969. Tcl_SetObjLength(obj, size + sizeof(Tcl_Obj *));
  2970. buf = Tcl_GetString(obj);
  2971. memcpy(buf, &obj, sizeof(&obj));
  2972. buf = (Tcl_Obj **)buf + 1;
  2973. return (buf);
  2974. }
  2975. static void *
  2976. tcl_db_realloc(ptr, size)
  2977. void *ptr;
  2978. size_t size;
  2979. {
  2980. Tcl_Obj *obj;
  2981. if (ptr == NULL)
  2982. return (tcl_db_malloc(size));
  2983. obj = *(Tcl_Obj **)((Tcl_Obj **)ptr - 1);
  2984. Tcl_SetObjLength(obj, size + sizeof(Tcl_Obj *));
  2985. ptr = Tcl_GetString(obj);
  2986. memcpy(ptr, &obj, sizeof(&obj));
  2987. ptr = (Tcl_Obj **)ptr + 1;
  2988. return (ptr);
  2989. }
  2990. static void
  2991. tcl_db_free(ptr)
  2992. void *ptr;
  2993. {
  2994. Tcl_Obj *obj;
  2995. obj = *(Tcl_Obj **)((Tcl_Obj **)ptr - 1);
  2996. Tcl_DecrRefCount(obj);
  2997. }
  2998. #endif