diff options
author | Zhang Qiang <qiang.z.zhang@intel.com> | 2012-05-29 12:22:00 +0800 |
---|---|---|
committer | Zhang Qiang <qiang.z.zhang@intel.com> | 2012-05-29 12:22:00 +0800 |
commit | 02f0634ac29e19c68279e5544cac963e7f1203b8 (patch) | |
tree | b983472f94ef063cedf866d8ecfb55939171779d /tcl/tcl_env.c | |
parent | e776056ea09ba0b6d9505ced6913c9190a12d632 (diff) | |
download | db4-1.0_post.tar.gz db4-1.0_post.tar.bz2 db4-1.0_post.zip |
Diffstat (limited to 'tcl/tcl_env.c')
-rw-r--r-- | tcl/tcl_env.c | 2670 |
1 files changed, 2670 insertions, 0 deletions
diff --git a/tcl/tcl_env.c b/tcl/tcl_env.c new file mode 100644 index 0000000..15d7b70 --- /dev/null +++ b/tcl/tcl_env.c @@ -0,0 +1,2670 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1999-2009 Oracle. All rights reserved. + * + * $Id$ + */ + +#include "db_config.h" + +#include "db_int.h" +#ifdef HAVE_SYSTEM_INCLUDE_FILES +#include <tcl.h> +#endif +#include "dbinc/lock.h" +#include "dbinc/txn.h" +#include "dbinc/tcl_db.h" + +/* + * Prototypes for procedures defined later in this file: + */ +static void _EnvInfoDelete __P((Tcl_Interp *, DBTCL_INFO *)); +static int env_DbRemove __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB_ENV *)); +static int env_DbRename __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB_ENV *)); +static int env_GetFlags __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB_ENV *)); +static int env_GetOpenFlag + __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB_ENV *)); +static int env_GetLockDetect + __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB_ENV *)); +static int env_GetTimeout __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB_ENV *)); +static int env_GetVerbose __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB_ENV *)); + +/* + * PUBLIC: int env_Cmd __P((ClientData, Tcl_Interp *, int, Tcl_Obj * CONST*)); + * + * env_Cmd -- + * Implements the "env" command. + */ +int +env_Cmd(clientData, interp, objc, objv) + ClientData clientData; /* Env handle */ + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ +{ + static const char *envcmds[] = { +#ifdef CONFIG_TEST + "attributes", + "errfile", + "errpfx", + "event", + "failchk", + "id_reset", + "lock_detect", + "lock_id", + "lock_id_free", + "lock_id_set", + "lock_get", + "lock_stat", + "lock_timeout", + "lock_vec", + "log_archive", + "log_compare", + "log_config", + "log_cursor", + "log_file", + "log_flush", + "log_get", + "log_get_config", + "log_put", + "log_stat", + "lsn_reset", + "mpool", + "mpool_stat", + "mpool_sync", + "mpool_trickle", + "mutex", + "mutex_free", + "mutex_get_align", + "mutex_get_incr", + "mutex_get_max", + "mutex_get_tas_spins", + "mutex_lock", + "mutex_set_tas_spins", + "mutex_stat", + "mutex_unlock", + "rep_config", + "rep_elect", + "rep_flush", + "rep_get_clockskew", + "rep_get_config", + "rep_get_limit", + "rep_get_nsites", + "rep_get_request", + "rep_get_timeout", + "rep_lease", + "rep_limit", + "rep_process_message", + "rep_request", + "rep_start", + "rep_stat", + "rep_sync", + "rep_transport", + "repmgr", + "repmgr_site_list", + "repmgr_stat", + "rpcid", + "set_flags", + "test", + "txn_id_set", + "txn_recover", + "txn_stat", + "txn_timeout", + "verbose", +#endif + "cdsgroup", + "close", + "dbremove", + "dbrename", + "get_cachesize", + "get_cache_max", + "get_data_dirs", + "get_encrypt_flags", + "get_errpfx", + "get_flags", + "get_home", + "get_lg_bsize", + "get_lg_dir", + "get_lg_filemode", + "get_lg_max", + "get_lg_regionmax", + "get_lk_detect", + "get_lk_max_lockers", + "get_lk_max_locks", + "get_lk_max_objects", + "get_mp_max_openfd", + "get_mp_max_write", + "get_mp_mmapsize", + "get_open_flags", + "get_shm_key", + "get_tas_spins", + "get_timeout", + "get_tmp_dir", + "get_tx_max", + "get_tx_timestamp", + "get_verbose", + "resize_cache", + "set_data_dir", + "txn", + "txn_checkpoint", + NULL + }; + enum envcmds { +#ifdef CONFIG_TEST + ENVATTR, + ENVERRFILE, + ENVERRPFX, + ENVEVENT, + ENVFAILCHK, + ENVIDRESET, + ENVLKDETECT, + ENVLKID, + ENVLKFREEID, + ENVLKSETID, + ENVLKGET, + ENVLKSTAT, + ENVLKTIMEOUT, + ENVLKVEC, + ENVLOGARCH, + ENVLOGCMP, + ENVLOGCONFIG, + ENVLOGCURSOR, + ENVLOGFILE, + ENVLOGFLUSH, + ENVLOGGET, + ENVLOGGETCONFIG, + ENVLOGPUT, + ENVLOGSTAT, + ENVLSNRESET, + ENVMP, + ENVMPSTAT, + ENVMPSYNC, + ENVTRICKLE, + ENVMUTEX, + ENVMUTFREE, + ENVMUTGETALIGN, + ENVMUTGETINCR, + ENVMUTGETMAX, + ENVMUTGETTASSPINS, + ENVMUTLOCK, + ENVMUTSETTASSPINS, + ENVMUTSTAT, + ENVMUTUNLOCK, + ENVREPCONFIG, + ENVREPELECT, + ENVREPFLUSH, + ENVREPGETCLOCKSKEW, + ENVREPGETCONFIG, + ENVREPGETLIMIT, + ENVREPGETNSITES, + ENVREPGETREQUEST, + ENVREPGETTIMEOUT, + ENVREPLEASE, + ENVREPLIMIT, + ENVREPPROCMESS, + ENVREPREQUEST, + ENVREPSTART, + ENVREPSTAT, + ENVREPSYNC, + ENVREPTRANSPORT, + ENVREPMGR, + ENVREPMGRSITELIST, + ENVREPMGRSTAT, + ENVRPCID, + ENVSETFLAGS, + ENVTEST, + ENVTXNSETID, + ENVTXNRECOVER, + ENVTXNSTAT, + ENVTXNTIMEOUT, + ENVVERB, +#endif + ENVCDSGROUP, + ENVCLOSE, + ENVDBREMOVE, + ENVDBRENAME, + ENVGETCACHESIZE, + ENVGETCACHEMAX, + ENVGETDATADIRS, + ENVGETENCRYPTFLAGS, + ENVGETERRPFX, + ENVGETFLAGS, + ENVGETHOME, + ENVGETLGBSIZE, + ENVGETLGDIR, + ENVGETLGFILEMODE, + ENVGETLGMAX, + ENVGETLGREGIONMAX, + ENVGETLKDETECT, + ENVGETLKMAXLOCKERS, + ENVGETLKMAXLOCKS, + ENVGETLKMAXOBJECTS, + ENVGETMPMAXOPENFD, + ENVGETMPMAXWRITE, + ENVGETMPMMAPSIZE, + ENVGETOPENFLAG, + ENVGETSHMKEY, + ENVGETTASSPINS, + ENVGETTIMEOUT, + ENVGETTMPDIR, + ENVGETTXMAX, + ENVGETTXTIMESTAMP, + ENVGETVERBOSE, + ENVRESIZECACHE, + ENVSETDATADIR, + ENVTXN, + ENVTXNCKP + }; + DBTCL_INFO *envip; + DB_ENV *dbenv; + Tcl_Obj **listobjv, *myobjv[3], *res; + db_timeout_t timeout; + size_t size; + time_t timeval; + u_int32_t bytes, gbytes, value; + long shm_key; + int cmdindex, i, intvalue, listobjc, ncache, result, ret; + const char *strval, **dirs; + char *strarg, newname[MSG_SIZE]; +#ifdef CONFIG_TEST + DBTCL_INFO *logcip; + DB_LOGC *logc; + u_int32_t lockid; + long newval, otherval; +#endif + + Tcl_ResetResult(interp); + dbenv = (DB_ENV *)clientData; + envip = _PtrToInfo((void *)dbenv); + result = TCL_OK; + memset(newname, 0, MSG_SIZE); + + if (objc <= 1) { + Tcl_WrongNumArgs(interp, 1, objv, "command cmdargs"); + return (TCL_ERROR); + } + if (dbenv == NULL) { + Tcl_SetResult(interp, "NULL env pointer", TCL_STATIC); + return (TCL_ERROR); + } + if (envip == NULL) { + Tcl_SetResult(interp, "NULL env info pointer", TCL_STATIC); + return (TCL_ERROR); + } + + /* + * Get the command name index from the object based on the berkdbcmds + * defined above. + */ + if (Tcl_GetIndexFromObj(interp, objv[1], envcmds, "command", + TCL_EXACT, &cmdindex) != TCL_OK) + return (IS_HELP(objv[1])); + res = NULL; + switch ((enum envcmds)cmdindex) { +#ifdef CONFIG_TEST + case ENVEVENT: + /* + * Two args for this. Error if different. + */ + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, NULL); + return (TCL_ERROR); + } + result = tcl_EventNotify(interp, dbenv, objv[2], envip); + break; + case ENVFAILCHK: + /* + * No args for this. Error if there are some. + */ + if (objc > 2) { + Tcl_WrongNumArgs(interp, 2, objv, NULL); + return (TCL_ERROR); + } + _debug_check(); + ret = dbenv->failchk(dbenv, 0); + result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), + "failchk"); + break; + case ENVIDRESET: + result = tcl_EnvIdReset(interp, objc, objv, dbenv); + break; + case ENVLSNRESET: + result = tcl_EnvLsnReset(interp, objc, objv, dbenv); + break; + case ENVLKDETECT: + result = tcl_LockDetect(interp, objc, objv, dbenv); + break; + case ENVLKSTAT: + result = tcl_LockStat(interp, objc, objv, dbenv); + break; + case ENVLKTIMEOUT: + result = tcl_LockTimeout(interp, objc, objv, dbenv); + break; + case ENVLKID: + /* + * No args for this. Error if there are some. + */ + if (objc > 2) { + Tcl_WrongNumArgs(interp, 2, objv, NULL); + return (TCL_ERROR); + } + _debug_check(); + ret = dbenv->lock_id(dbenv, &lockid); + result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), + "lock_id"); + if (result == TCL_OK) + res = Tcl_NewWideIntObj((Tcl_WideInt)lockid); + break; + case ENVLKFREEID: + if (objc != 3) { + Tcl_WrongNumArgs(interp, 3, objv, NULL); + return (TCL_ERROR); + } + result = Tcl_GetLongFromObj(interp, objv[2], &newval); + if (result != TCL_OK) + return (result); + ret = dbenv->lock_id_free(dbenv, (u_int32_t)newval); + result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), + "lock id_free"); + break; + case ENVLKSETID: + if (objc != 4) { + Tcl_WrongNumArgs(interp, 4, objv, "current max"); + return (TCL_ERROR); + } + result = Tcl_GetLongFromObj(interp, objv[2], &newval); + if (result != TCL_OK) + return (result); + result = Tcl_GetLongFromObj(interp, objv[3], &otherval); + if (result != TCL_OK) + return (result); + ret = __lock_id_set(dbenv->env, + (u_int32_t)newval, (u_int32_t)otherval); + result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), + "lock id_free"); + break; + case ENVLKGET: + result = tcl_LockGet(interp, objc, objv, dbenv); + break; + case ENVLKVEC: + result = tcl_LockVec(interp, objc, objv, dbenv); + break; + case ENVLOGARCH: + result = tcl_LogArchive(interp, objc, objv, dbenv); + break; + case ENVLOGCMP: + result = tcl_LogCompare(interp, objc, objv); + break; + case ENVLOGCONFIG: + /* + * Two args for this. Error if different. + */ + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, NULL); + return (TCL_ERROR); + } + result = tcl_LogConfig(interp, dbenv, objv[2]); + break; + case ENVLOGCURSOR: + snprintf(newname, sizeof(newname), + "%s.logc%d", envip->i_name, envip->i_envlogcid); + logcip = _NewInfo(interp, NULL, newname, I_LOGC); + if (logcip != NULL) { + ret = dbenv->log_cursor(dbenv, &logc, 0); + if (ret == 0) { + result = TCL_OK; + envip->i_envlogcid++; + /* + * We do NOT want to set i_parent to + * envip here because log cursors are + * not "tied" to the env. That is, they + * are NOT closed if the env is closed. + */ + (void)Tcl_CreateObjCommand(interp, newname, + (Tcl_ObjCmdProc *)logc_Cmd, + (ClientData)logc, NULL); + res = NewStringObj(newname, strlen(newname)); + _SetInfoData(logcip, logc); + } else { + _DeleteInfo(logcip); + result = _ErrorSetup(interp, ret, "log cursor"); + } + } else { + Tcl_SetResult(interp, + "Could not set up info", TCL_STATIC); + result = TCL_ERROR; + } + break; + case ENVLOGFILE: + result = tcl_LogFile(interp, objc, objv, dbenv); + break; + case ENVLOGFLUSH: + result = tcl_LogFlush(interp, objc, objv, dbenv); + break; + case ENVLOGGET: + result = tcl_LogGet(interp, objc, objv, dbenv); + break; + case ENVLOGGETCONFIG: + /* + * Two args for this. Error if different. + */ + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, NULL); + return (TCL_ERROR); + } + result = tcl_LogGetConfig(interp, dbenv, objv[2]); + break; + case ENVLOGPUT: + result = tcl_LogPut(interp, objc, objv, dbenv); + break; + case ENVLOGSTAT: + result = tcl_LogStat(interp, objc, objv, dbenv); + break; + case ENVMPSTAT: + result = tcl_MpStat(interp, objc, objv, dbenv); + break; + case ENVMPSYNC: + result = tcl_MpSync(interp, objc, objv, dbenv); + break; + case ENVTRICKLE: + result = tcl_MpTrickle(interp, objc, objv, dbenv); + break; + case ENVMP: + result = tcl_Mp(interp, objc, objv, dbenv, envip); + break; + case ENVMUTEX: + result = tcl_Mutex(interp, objc, objv, dbenv); + break; + case ENVMUTFREE: + result = tcl_MutFree(interp, objc, objv, dbenv); + break; + case ENVMUTGETALIGN: + result = tcl_MutGet(interp, dbenv, DBTCL_MUT_ALIGN); + break; + case ENVMUTGETINCR: + result = tcl_MutGet(interp, dbenv, DBTCL_MUT_INCR); + break; + case ENVMUTGETMAX: + result = tcl_MutGet(interp, dbenv, DBTCL_MUT_MAX); + break; + case ENVMUTGETTASSPINS: + result = tcl_MutGet(interp, dbenv, DBTCL_MUT_TAS); + break; + case ENVMUTLOCK: + result = tcl_MutLock(interp, objc, objv, dbenv); + break; + case ENVMUTSETTASSPINS: + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, NULL); + return (TCL_ERROR); + } + result = tcl_MutSet(interp, objv[2], dbenv, DBTCL_MUT_TAS); + break; + case ENVMUTSTAT: + result = tcl_MutStat(interp, objc, objv, dbenv); + break; + case ENVMUTUNLOCK: + result = tcl_MutUnlock(interp, objc, objv, dbenv); + break; + case ENVREPCONFIG: + /* + * Two args for this. Error if different. + */ + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, NULL); + return (TCL_ERROR); + } + result = tcl_RepConfig(interp, dbenv, objv[2]); + break; + case ENVREPELECT: + result = tcl_RepElect(interp, objc, objv, dbenv); + break; + case ENVREPFLUSH: + result = tcl_RepFlush(interp, objc, objv, dbenv); + break; + case ENVREPGETCLOCKSKEW: + result = tcl_RepGetTwo(interp, dbenv, DBTCL_GETCLOCK); + break; + case ENVREPGETCONFIG: + /* + * Two args for this. Error if different. + */ + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, NULL); + return (TCL_ERROR); + } + result = tcl_RepGetConfig(interp, dbenv, objv[2]); + break; + case ENVREPGETLIMIT: + result = tcl_RepGetTwo(interp, dbenv, DBTCL_GETLIMIT); + break; + case ENVREPGETNSITES: + if (objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, NULL); + return (TCL_ERROR); + } + ret = dbenv->rep_get_nsites(dbenv, &value); + if ((result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), + "env rep_get_nsites")) == TCL_OK) + res = Tcl_NewLongObj((long)value); + break; + case ENVREPGETREQUEST: + result = tcl_RepGetTwo(interp, dbenv, DBTCL_GETREQ); + break; + case ENVREPGETTIMEOUT: + /* + * Two args for this. Error if different. + */ + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, NULL); + return (TCL_ERROR); + } + result = tcl_RepGetTimeout(interp, dbenv, objv[2]); + break; + case ENVREPLEASE: + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, NULL); + return (TCL_ERROR); + } + result = Tcl_ListObjGetElements(interp, objv[2], + &listobjc, &listobjv); + if (result == TCL_OK) + result = tcl_RepLease(interp, + listobjc, listobjv, dbenv); + break; + case ENVREPLIMIT: + result = tcl_RepLimit(interp, objc, objv, dbenv); + break; + case ENVREPPROCMESS: + result = tcl_RepProcessMessage(interp, objc, objv, dbenv); + break; + case ENVREPREQUEST: + result = tcl_RepRequest(interp, objc, objv, dbenv); + break; + case ENVREPSTART: + result = tcl_RepStart(interp, objc, objv, dbenv); + break; + case ENVREPSTAT: + result = tcl_RepStat(interp, objc, objv, dbenv); + break; + case ENVREPSYNC: + result = tcl_RepSync(interp, objc, objv, dbenv); + break; + case ENVREPTRANSPORT: + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, NULL); + return (TCL_ERROR); + } + result = Tcl_ListObjGetElements(interp, objv[2], + &listobjc, &listobjv); + if (result == TCL_OK) + result = tcl_RepTransport(interp, + listobjc, listobjv, dbenv, envip); + break; + case ENVREPMGR: + result = tcl_RepMgr(interp, objc, objv, dbenv); + break; + case ENVREPMGRSITELIST: + result = tcl_RepMgrSiteList(interp, objc, objv, dbenv); + break; + case ENVREPMGRSTAT: + result = tcl_RepMgrStat(interp, objc, objv, dbenv); + break; + case ENVRPCID: + /* + * No args for this. Error if there are some. + */ + if (objc > 2) { + Tcl_WrongNumArgs(interp, 2, objv, NULL); + return (TCL_ERROR); + } + /* + * !!! Retrieve the client ID from the dbp handle directly. + * This is for testing purposes only. It is BDB-private data. + */ + res = Tcl_NewLongObj((long)dbenv->cl_id); + break; + case ENVTXNSETID: + if (objc != 4) { + Tcl_WrongNumArgs(interp, 4, objv, "current max"); + return (TCL_ERROR); + } + result = Tcl_GetLongFromObj(interp, objv[2], &newval); + if (result != TCL_OK) + return (result); + result = Tcl_GetLongFromObj(interp, objv[3], &otherval); + if (result != TCL_OK) + return (result); + ret = __txn_id_set(dbenv->env, + (u_int32_t)newval, (u_int32_t)otherval); + result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), + "txn setid"); + break; + case ENVTXNRECOVER: + result = tcl_TxnRecover(interp, objc, objv, dbenv, envip); + break; + case ENVTXNSTAT: + result = tcl_TxnStat(interp, objc, objv, dbenv); + break; + case ENVTXNTIMEOUT: + result = tcl_TxnTimeout(interp, objc, objv, dbenv); + break; + case ENVATTR: + result = tcl_EnvAttr(interp, objc, objv, dbenv); + break; + case ENVERRFILE: + /* + * One args for this. Error if different. + */ + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "errfile"); + return (TCL_ERROR); + } + strarg = Tcl_GetStringFromObj(objv[2], NULL); + tcl_EnvSetErrfile(interp, dbenv, envip, strarg); + result = TCL_OK; + break; + case ENVERRPFX: + /* + * One args for this. Error if different. + */ + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "pfx"); + return (TCL_ERROR); + } + strarg = Tcl_GetStringFromObj(objv[2], NULL); + result = tcl_EnvSetErrpfx(interp, dbenv, envip, strarg); + break; + case ENVSETFLAGS: + /* + * Two args for this. Error if different. + */ + if (objc != 4) { + Tcl_WrongNumArgs(interp, 2, objv, "which on|off"); + return (TCL_ERROR); + } + result = tcl_EnvSetFlags(interp, dbenv, objv[2], objv[3]); + break; + case ENVTEST: + result = tcl_EnvTest(interp, objc, objv, dbenv); + break; + case ENVVERB: + /* + * Two args for this. Error if different. + */ + if (objc != 4) { + Tcl_WrongNumArgs(interp, 2, objv, NULL); + return (TCL_ERROR); + } + result = tcl_EnvVerbose(interp, dbenv, objv[2], objv[3]); + break; +#endif + case ENVCDSGROUP: + result = tcl_CDSGroup(interp, objc, objv, dbenv, envip); + break; + case ENVCLOSE: + /* + * No args for this. Error if there are some. + */ + if (objc > 2) { + Tcl_WrongNumArgs(interp, 2, objv, NULL); + return (TCL_ERROR); + } + /* + * Any transactions will be aborted, and an mpools + * closed automatically. We must delete any txn + * and mp widgets we have here too for this env. + * NOTE: envip is freed when we come back from + * this function. Set it to NULL to make sure no + * one tries to use it later. + */ + _debug_check(); + ret = dbenv->close(dbenv, 0); + result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), + "env close"); + _EnvInfoDelete(interp, envip); + envip = NULL; + break; + case ENVDBREMOVE: + result = env_DbRemove(interp, objc, objv, dbenv); + break; + case ENVDBRENAME: + result = env_DbRename(interp, objc, objv, dbenv); + break; + case ENVGETCACHESIZE: + if (objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, NULL); + return (TCL_ERROR); + } + ret = dbenv->get_cachesize(dbenv, &gbytes, &bytes, &ncache); + if ((result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), + "env get_cachesize")) == TCL_OK) { + myobjv[0] = Tcl_NewLongObj((long)gbytes); + myobjv[1] = Tcl_NewLongObj((long)bytes); + myobjv[2] = Tcl_NewLongObj((long)ncache); + res = Tcl_NewListObj(3, myobjv); + } + break; + case ENVGETCACHEMAX: + if (objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, NULL); + return (TCL_ERROR); + } + ret = dbenv->get_cache_max(dbenv, &gbytes, &bytes); + if ((result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), + "env get_cache_max")) == TCL_OK) { + myobjv[0] = Tcl_NewLongObj((long)gbytes); + myobjv[1] = Tcl_NewLongObj((long)bytes); + res = Tcl_NewListObj(2, myobjv); + } + break; + case ENVGETDATADIRS: + if (objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, NULL); + return (TCL_ERROR); + } + ret = dbenv->get_data_dirs(dbenv, &dirs); + if ((result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), + "env get_data_dirs")) == TCL_OK) { + res = Tcl_NewListObj(0, NULL); + for (i = 0; result == TCL_OK && dirs[i] != NULL; i++) + result = Tcl_ListObjAppendElement(interp, res, + NewStringObj(dirs[i], strlen(dirs[i]))); + } + break; + case ENVGETENCRYPTFLAGS: + result = tcl_EnvGetEncryptFlags(interp, objc, objv, dbenv); + break; + case ENVGETERRPFX: + if (objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, NULL); + return (TCL_ERROR); + } + dbenv->get_errpfx(dbenv, &strval); + res = NewStringObj(strval, strlen(strval)); + break; + case ENVGETFLAGS: + result = env_GetFlags(interp, objc, objv, dbenv); + break; + case ENVGETHOME: + if (objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, NULL); + return (TCL_ERROR); + } + ret = dbenv->get_home(dbenv, &strval); + if ((result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), + "env get_home")) == TCL_OK) + res = NewStringObj(strval, strlen(strval)); + break; + case ENVGETLGBSIZE: + if (objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, NULL); + return (TCL_ERROR); + } + ret = dbenv->get_lg_bsize(dbenv, &value); + if ((result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), + "env get_lg_bsize")) == TCL_OK) + res = Tcl_NewLongObj((long)value); + break; + case ENVGETLGDIR: + if (objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, NULL); + return (TCL_ERROR); + } + ret = dbenv->get_lg_dir(dbenv, &strval); + if ((result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), + "env get_lg_dir")) == TCL_OK) + res = NewStringObj(strval, strlen(strval)); + break; + case ENVGETLGFILEMODE: + if (objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, NULL); + return (TCL_ERROR); + } + ret = dbenv->get_lg_filemode(dbenv, &intvalue); + if ((result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), + "env get_lg_filemode")) == TCL_OK) + res = Tcl_NewLongObj((long)intvalue); + break; + case ENVGETLGMAX: + if (objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, NULL); + return (TCL_ERROR); + } + ret = dbenv->get_lg_max(dbenv, &value); + if ((result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), + "env get_lg_max")) == TCL_OK) + res = Tcl_NewLongObj((long)value); + break; + case ENVGETLGREGIONMAX: + if (objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, NULL); + return (TCL_ERROR); + } + ret = dbenv->get_lg_regionmax(dbenv, &value); + if ((result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), + "env get_lg_regionmax")) == TCL_OK) + res = Tcl_NewLongObj((long)value); + break; + case ENVGETLKDETECT: + result = env_GetLockDetect(interp, objc, objv, dbenv); + break; + case ENVGETLKMAXLOCKERS: + if (objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, NULL); + return (TCL_ERROR); + } + ret = dbenv->get_lk_max_lockers(dbenv, &value); + if ((result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), + "env get_lk_max_lockers")) == TCL_OK) + res = Tcl_NewLongObj((long)value); + break; + case ENVGETLKMAXLOCKS: + if (objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, NULL); + return (TCL_ERROR); + } + ret = dbenv->get_lk_max_locks(dbenv, &value); + if ((result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), + "env get_lk_max_locks")) == TCL_OK) + res = Tcl_NewLongObj((long)value); + break; + case ENVGETLKMAXOBJECTS: + if (objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, NULL); + return (TCL_ERROR); + } + ret = dbenv->get_lk_max_objects(dbenv, &value); + if ((result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), + "env get_lk_max_objects")) == TCL_OK) + res = Tcl_NewLongObj((long)value); + break; + case ENVGETMPMAXOPENFD: + if (objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, NULL); + return (TCL_ERROR); + } + ret = dbenv->get_mp_max_openfd(dbenv, &intvalue); + if ((result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), + "env get_mp_max_openfd")) == TCL_OK) + res = Tcl_NewIntObj(intvalue); + break; + case ENVGETMPMAXWRITE: + if (objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, NULL); + return (TCL_ERROR); + } + ret = dbenv->get_mp_max_write(dbenv, &intvalue, &timeout); + if ((result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), + "env get_mp_max_write")) == TCL_OK) { + myobjv[0] = Tcl_NewIntObj(intvalue); + myobjv[1] = Tcl_NewIntObj((int)timeout); + res = Tcl_NewListObj(2, myobjv); + } + break; + case ENVGETMPMMAPSIZE: + if (objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, NULL); + return (TCL_ERROR); + } + ret = dbenv->get_mp_mmapsize(dbenv, &size); + if ((result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), + "env get_mp_mmapsize")) == TCL_OK) + res = Tcl_NewLongObj((long)size); + break; + case ENVGETOPENFLAG: + result = env_GetOpenFlag(interp, objc, objv, dbenv); + break; + case ENVGETSHMKEY: + if (objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, NULL); + return (TCL_ERROR); + } + ret = dbenv->get_shm_key(dbenv, &shm_key); + if ((result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), + "env shm_key")) == TCL_OK) + res = Tcl_NewLongObj(shm_key); + break; + case ENVGETTASSPINS: + if (objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, NULL); + return (TCL_ERROR); + } + ret = dbenv->mutex_get_tas_spins(dbenv, &value); + if ((result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), + "env get_tas_spins")) == TCL_OK) + res = Tcl_NewLongObj((long)value); + break; + case ENVGETTIMEOUT: + result = env_GetTimeout(interp, objc, objv, dbenv); + break; + case ENVGETTMPDIR: + if (objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, NULL); + return (TCL_ERROR); + } + ret = dbenv->get_tmp_dir(dbenv, &strval); + if ((result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), + "env get_tmp_dir")) == TCL_OK) + res = NewStringObj(strval, strlen(strval)); + break; + case ENVGETTXMAX: + if (objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, NULL); + return (TCL_ERROR); + } + ret = dbenv->get_tx_max(dbenv, &value); + if ((result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), + "env get_tx_max")) == TCL_OK) + res = Tcl_NewLongObj((long)value); + break; + case ENVGETTXTIMESTAMP: + if (objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, NULL); + return (TCL_ERROR); + } + ret = dbenv->get_tx_timestamp(dbenv, &timeval); + if ((result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), + "env get_tx_timestamp")) == TCL_OK) + res = Tcl_NewLongObj((long)timeval); + break; + case ENVGETVERBOSE: + result = env_GetVerbose(interp, objc, objv, dbenv); + break; + case ENVRESIZECACHE: + if ((result = Tcl_ListObjGetElements( + interp, objv[2], &listobjc, &listobjv)) != TCL_OK) + break; + if (objc != 3 || listobjc != 2) { + Tcl_WrongNumArgs(interp, 2, objv, + "?-resize_cache {gbytes bytes}?"); + result = TCL_ERROR; + break; + } + result = _GetUInt32(interp, listobjv[0], &gbytes); + if (result != TCL_OK) + break; + result = _GetUInt32(interp, listobjv[1], &bytes); + if (result != TCL_OK) + break; + ret = dbenv->set_cachesize(dbenv, gbytes, bytes, 0); + result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), + "resize_cache"); + break; + case ENVSETDATADIR: + /* + * One args for this. Error if different. + */ + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "pfx"); + return (TCL_ERROR); + } + strarg = Tcl_GetStringFromObj(objv[2], NULL); + ret = dbenv->set_data_dir(dbenv, strarg); + return (_ReturnSetup(interp, ret, DB_RETOK_STD(ret), + "env set data dir")); + case ENVTXN: + result = tcl_Txn(interp, objc, objv, dbenv, envip); + break; + case ENVTXNCKP: + result = tcl_TxnCheckpoint(interp, objc, objv, dbenv); + break; + } + /* + * Only set result if we have a res. Otherwise, lower + * functions have already done so. + */ + if (result == TCL_OK && res) + Tcl_SetObjResult(interp, res); + return (result); +} + +/* + * PUBLIC: int tcl_EnvRemove __P((Tcl_Interp *, int, Tcl_Obj * CONST*, + * PUBLIC: DB_ENV *, DBTCL_INFO *)); + * + * tcl_EnvRemove -- + */ +int +tcl_EnvRemove(interp, objc, objv, dbenv, envip) + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ + DB_ENV *dbenv; /* Env pointer */ + DBTCL_INFO *envip; /* Info pointer */ +{ + static const char *envremopts[] = { +#ifdef CONFIG_TEST + "-overwrite", + "-server", +#endif + "-data_dir", + "-encryptaes", + "-encryptany", + "-force", + "-home", + "-log_dir", + "-tmp_dir", + "-use_environ", + "-use_environ_root", + NULL + }; + enum envremopts { +#ifdef CONFIG_TEST + ENVREM_OVERWRITE, + ENVREM_SERVER, +#endif + ENVREM_DATADIR, + ENVREM_ENCRYPT_AES, + ENVREM_ENCRYPT_ANY, + ENVREM_FORCE, + ENVREM_HOME, + ENVREM_LOGDIR, + ENVREM_TMPDIR, + ENVREM_USE_ENVIRON, + ENVREM_USE_ENVIRON_ROOT + }; + u_int32_t cflag, enc_flag, flag, forceflag, sflag; + int i, optindex, result, ret; + char *datadir, *home, *logdir, *passwd, *server, *tmpdir; + + result = TCL_OK; + cflag = flag = forceflag = sflag = 0; + home = NULL; + passwd = NULL; + datadir = logdir = tmpdir = NULL; + server = NULL; + enc_flag = 0; + + if (objc < 2) { + Tcl_WrongNumArgs(interp, 2, objv, "?args?"); + return (TCL_ERROR); + } + + i = 2; + while (i < objc) { + if (Tcl_GetIndexFromObj(interp, objv[i], envremopts, "option", + TCL_EXACT, &optindex) != TCL_OK) { + result = IS_HELP(objv[i]); + goto error; + } + i++; + switch ((enum envremopts)optindex) { +#ifdef CONFIG_TEST + case ENVREM_SERVER: + /* Make sure we have an arg to check against! */ + if (i >= objc) { + Tcl_WrongNumArgs(interp, 2, objv, + "?-server name?"); + result = TCL_ERROR; + break; + } + server = Tcl_GetStringFromObj(objv[i++], NULL); + cflag = DB_RPCCLIENT; + break; +#endif + case ENVREM_ENCRYPT_AES: + /* Make sure we have an arg to check against! */ + if (i >= objc) { + Tcl_WrongNumArgs(interp, 2, objv, + "?-encryptaes passwd?"); + result = TCL_ERROR; + break; + } + passwd = Tcl_GetStringFromObj(objv[i++], NULL); + enc_flag = DB_ENCRYPT_AES; + break; + case ENVREM_ENCRYPT_ANY: + /* Make sure we have an arg to check against! */ + if (i >= objc) { + Tcl_WrongNumArgs(interp, 2, objv, + "?-encryptany passwd?"); + result = TCL_ERROR; + break; + } + passwd = Tcl_GetStringFromObj(objv[i++], NULL); + enc_flag = 0; + break; + case ENVREM_FORCE: + forceflag |= DB_FORCE; + break; + case ENVREM_HOME: + /* Make sure we have an arg to check against! */ + if (i >= objc) { + Tcl_WrongNumArgs(interp, 2, objv, + "?-home dir?"); + result = TCL_ERROR; + break; + } + home = Tcl_GetStringFromObj(objv[i++], NULL); + break; +#ifdef CONFIG_TEST + case ENVREM_OVERWRITE: + sflag |= DB_OVERWRITE; + break; +#endif + case ENVREM_USE_ENVIRON: + flag |= DB_USE_ENVIRON; + break; + case ENVREM_USE_ENVIRON_ROOT: + flag |= DB_USE_ENVIRON_ROOT; + break; + case ENVREM_DATADIR: + if (i >= objc) { + Tcl_WrongNumArgs(interp, 2, objv, + "-data_dir dir"); + result = TCL_ERROR; + break; + } + datadir = Tcl_GetStringFromObj(objv[i++], NULL); + break; + case ENVREM_LOGDIR: + if (i >= objc) { + Tcl_WrongNumArgs(interp, 2, objv, + "-log_dir dir"); + result = TCL_ERROR; + break; + } + logdir = Tcl_GetStringFromObj(objv[i++], NULL); + break; + case ENVREM_TMPDIR: + if (i >= objc) { + Tcl_WrongNumArgs(interp, 2, objv, + "-tmp_dir dir"); + result = TCL_ERROR; + break; + } + tmpdir = Tcl_GetStringFromObj(objv[i++], NULL); + break; + } + /* + * If, at any time, parsing the args we get an error, + * bail out and return. + */ + if (result != TCL_OK) + goto error; + } + + /* + * If dbenv is NULL, we don't have an open env and we need to open + * one of the user. Don't bother with the info stuff. + */ + if (dbenv == NULL) { + if ((ret = db_env_create(&dbenv, cflag)) != 0) { + result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), + "db_env_create"); + goto error; + } + if (server != NULL) { + _debug_check(); + ret = dbenv->set_rpc_server( + dbenv, NULL, server, 0, 0, 0); + result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), + "set_rpc_server"); + if (result != TCL_OK) + goto error; + } + if (datadir != NULL) { + _debug_check(); + ret = dbenv->set_data_dir(dbenv, datadir); + result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), + "set_data_dir"); + if (result != TCL_OK) + goto error; + } + if (logdir != NULL) { + _debug_check(); + ret = dbenv->set_lg_dir(dbenv, logdir); + result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), + "set_log_dir"); + if (result != TCL_OK) + goto error; + } + if (tmpdir != NULL) { + _debug_check(); + ret = dbenv->set_tmp_dir(dbenv, tmpdir); + result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), + "set_tmp_dir"); + if (result != TCL_OK) + goto error; + } + if (passwd != NULL) { + ret = dbenv->set_encrypt(dbenv, passwd, enc_flag); + result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), + "set_encrypt"); + } + if (sflag != 0 && + (ret = dbenv->set_flags(dbenv, sflag, 1)) != 0) { + _debug_check(); + result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), + "set_flags"); + if (result != TCL_OK) + goto error; + } + dbenv->set_errpfx(dbenv, "EnvRemove"); + dbenv->set_errcall(dbenv, _ErrorFunc); + } else { + /* + * We have to clean up any info associated with this env, + * regardless of the result of the remove so do it first. + * NOTE: envip is freed when we come back from this function. + */ + _EnvInfoDelete(interp, envip); + envip = NULL; + } + + flag |= forceflag; + /* + * When we get here we have parsed all the args. Now remove + * the environment. + */ + _debug_check(); + ret = dbenv->remove(dbenv, home, flag); + result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "env remove"); +error: + return (result); +} + +static void +_EnvInfoDelete(interp, envip) + Tcl_Interp *interp; /* Tcl Interpreter */ + DBTCL_INFO *envip; /* Info for env */ +{ + DBTCL_INFO *nextp, *p; + + /* + * Before we can delete the environment info, we must close + * any open subsystems in this env. We will: + * 1. Abort any transactions (which aborts any nested txns). + * 2. Close any mpools (which will put any pages itself). + * 3. Put any locks and close log cursors. + * 4. Close the error file. + */ + for (p = LIST_FIRST(&__db_infohead); p != NULL; p = nextp) { + /* + * Check if this info structure "belongs" to this + * env. If so, remove its commands and info structure. + * We do not close/abort/whatever here, because we + * don't want to replicate DB behavior. + * + * NOTE: Only those types that can nest need to be + * itemized in the switch below. That is txns and mps. + * Other types like log cursors and locks will just + * get cleaned up here. + */ + if (p->i_parent == envip) { + switch (p->i_type) { + case I_TXN: + _TxnInfoDelete(interp, p); + break; + case I_MP: + _MpInfoDelete(interp, p); + break; + case I_DB: + case I_DBC: + case I_ENV: + case I_LOCK: + case I_LOGC: + case I_NDBM: + case I_PG: + case I_SEQ: + Tcl_SetResult(interp, + "_EnvInfoDelete: bad info type", + TCL_STATIC); + break; + } + nextp = LIST_NEXT(p, entries); + (void)Tcl_DeleteCommand(interp, p->i_name); + _DeleteInfo(p); + } else + nextp = LIST_NEXT(p, entries); + } + (void)Tcl_DeleteCommand(interp, envip->i_name); + _DeleteInfo(envip); +} + +#ifdef CONFIG_TEST +/* + * PUBLIC: int tcl_EnvIdReset __P((Tcl_Interp *, int, Tcl_Obj * CONST*, + * PUBLIC: DB_ENV *)); + * + * tcl_EnvIdReset -- + * Implements the ENV->fileid_reset command. + */ +int +tcl_EnvIdReset(interp, objc, objv, dbenv) + Tcl_Interp *interp; /* Interpreter */ + int objc; /* arg count */ + Tcl_Obj * CONST* objv; /* args */ + DB_ENV *dbenv; /* Database pointer */ +{ + static const char *idwhich[] = { + "-encrypt", + NULL + }; + enum idwhich { + IDENCRYPT + }; + int enc, i, result, ret; + u_int32_t flags; + char *file; + + result = TCL_OK; + flags = 0; + i = 2; + Tcl_SetResult(interp, "0", TCL_STATIC); + if (objc < 3) { + Tcl_WrongNumArgs(interp, 2, objv, "?-encrypt? filename"); + return (TCL_ERROR); + } else if (objc > 3) { + /* + * If there is an arg, make sure it is the right one. + */ + if (Tcl_GetIndexFromObj(interp, objv[2], idwhich, "option", + TCL_EXACT, &enc) != TCL_OK) + return (IS_HELP(objv[2])); + switch ((enum idwhich)enc) { + case IDENCRYPT: + flags |= DB_ENCRYPT; + break; + } + i = 3; + } + file = Tcl_GetStringFromObj(objv[i], NULL); + ret = dbenv->fileid_reset(dbenv, file, flags); + result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "fileid reset"); + return (result); +} + +/* + * PUBLIC: int tcl_EnvLsnReset __P((Tcl_Interp *, int, Tcl_Obj * CONST*, + * PUBLIC: DB_ENV *)); + * + * tcl_EnvLsnReset -- + * Implements the ENV->lsn_reset command. + */ +int +tcl_EnvLsnReset(interp, objc, objv, dbenv) + Tcl_Interp *interp; /* Interpreter */ + int objc; /* arg count */ + Tcl_Obj * CONST* objv; /* args */ + DB_ENV *dbenv; /* Database pointer */ +{ + static const char *lsnwhich[] = { + "-encrypt", + NULL + }; + enum lsnwhich { + IDENCRYPT + }; + int enc, i, result, ret; + u_int32_t flags; + char *file; + + result = TCL_OK; + flags = 0; + i = 2; + Tcl_SetResult(interp, "0", TCL_STATIC); + if (objc < 3) { + Tcl_WrongNumArgs(interp, 2, objv, "?-encrypt? filename"); + return (TCL_ERROR); + } else if (objc > 3) { + /* + * If there is an arg, make sure it is the right one. + */ + if (Tcl_GetIndexFromObj(interp, objv[2], lsnwhich, "option", + TCL_EXACT, &enc) != TCL_OK) + return (IS_HELP(objv[2])); + + switch ((enum lsnwhich)enc) { + case IDENCRYPT: + flags |= DB_ENCRYPT; + break; + } + i = 3; + } + file = Tcl_GetStringFromObj(objv[i], NULL); + ret = dbenv->lsn_reset(dbenv, file, flags); + result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "lsn reset"); + return (result); +} + +/* + * PUBLIC: int tcl_EnvVerbose __P((Tcl_Interp *, DB_ENV *, Tcl_Obj *, + * PUBLIC: Tcl_Obj *)); + * + * tcl_EnvVerbose -- + */ +int +tcl_EnvVerbose(interp, dbenv, which, onoff) + Tcl_Interp *interp; /* Interpreter */ + DB_ENV *dbenv; /* Env pointer */ + Tcl_Obj *which; /* Which subsystem */ + Tcl_Obj *onoff; /* On or off */ +{ + static const char *verbwhich[] = { + "deadlock", + "fileops", + "fileops_all", + "recovery", + "register", + "rep", + "rep_elect", + "rep_lease", + "rep_misc", + "rep_msgs", + "rep_sync", + "rep_test", + "repmgr_connfail", + "repmgr_misc", + "wait", + NULL + }; + enum verbwhich { + ENVVERB_DEADLOCK, + ENVVERB_FILEOPS, + ENVVERB_FILEOPS_ALL, + ENVVERB_RECOVERY, + ENVVERB_REGISTER, + ENVVERB_REPLICATION, + ENVVERB_REP_ELECT, + ENVVERB_REP_LEASE, + ENVVERB_REP_MISC, + ENVVERB_REP_MSGS, + ENVVERB_REP_SYNC, + ENVVERB_REP_TEST, + ENVVERB_REPMGR_CONNFAIL, + ENVVERB_REPMGR_MISC, + ENVVERB_WAITSFOR + }; + static const char *verbonoff[] = { + "off", + "on", + NULL + }; + enum verbonoff { + ENVVERB_OFF, + ENVVERB_ON + }; + int on, optindex, ret; + u_int32_t wh; + + if (Tcl_GetIndexFromObj(interp, which, verbwhich, "option", + TCL_EXACT, &optindex) != TCL_OK) + return (IS_HELP(which)); + + switch ((enum verbwhich)optindex) { + case ENVVERB_DEADLOCK: + wh = DB_VERB_DEADLOCK; + break; + case ENVVERB_FILEOPS: + wh = DB_VERB_FILEOPS; + break; + case ENVVERB_FILEOPS_ALL: + wh = DB_VERB_FILEOPS_ALL; + break; + case ENVVERB_RECOVERY: + wh = DB_VERB_RECOVERY; + break; + case ENVVERB_REGISTER: + wh = DB_VERB_REGISTER; + break; + case ENVVERB_REPLICATION: + wh = DB_VERB_REPLICATION; + break; + case ENVVERB_REP_ELECT: + wh = DB_VERB_REP_ELECT; + break; + case ENVVERB_REP_LEASE: + wh = DB_VERB_REP_LEASE; + break; + case ENVVERB_REP_MISC: + wh = DB_VERB_REP_MISC; + break; + case ENVVERB_REP_MSGS: + wh = DB_VERB_REP_MSGS; + break; + case ENVVERB_REP_SYNC: + wh = DB_VERB_REP_SYNC; + break; + case ENVVERB_REP_TEST: + wh = DB_VERB_REP_TEST; + break; + case ENVVERB_REPMGR_CONNFAIL: + wh = DB_VERB_REPMGR_CONNFAIL; + break; + case ENVVERB_REPMGR_MISC: + wh = DB_VERB_REPMGR_MISC; + break; + case ENVVERB_WAITSFOR: + wh = DB_VERB_WAITSFOR; + break; + default: + return (TCL_ERROR); + } + if (Tcl_GetIndexFromObj(interp, onoff, verbonoff, "option", + TCL_EXACT, &optindex) != TCL_OK) + return (IS_HELP(onoff)); + switch ((enum verbonoff)optindex) { + case ENVVERB_OFF: + on = 0; + break; + case ENVVERB_ON: + on = 1; + break; + default: + return (TCL_ERROR); + } + ret = dbenv->set_verbose(dbenv, wh, on); + return (_ReturnSetup(interp, ret, DB_RETOK_STD(ret), + "env set verbose")); +} +#endif + +#ifdef CONFIG_TEST +/* + * PUBLIC: int tcl_EnvAttr __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB_ENV *)); + * + * tcl_EnvAttr -- + * Return a list of the env's attributes + */ +int +tcl_EnvAttr(interp, objc, objv, dbenv) + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ + DB_ENV *dbenv; /* Env pointer */ +{ + ENV *env; + Tcl_Obj *myobj, *retlist; + int result; + + env = dbenv->env; + result = TCL_OK; + + if (objc > 2) { + Tcl_WrongNumArgs(interp, 2, objv, NULL); + return (TCL_ERROR); + } + retlist = Tcl_NewListObj(0, NULL); + /* + * XXX + * We peek at the ENV to determine what subsystems we have available + * in this environment. + */ + myobj = NewStringObj("-home", strlen("-home")); + if ((result = Tcl_ListObjAppendElement(interp, + retlist, myobj)) != TCL_OK) + goto err; + myobj = NewStringObj(env->db_home, strlen(env->db_home)); + if ((result = Tcl_ListObjAppendElement(interp, + retlist, myobj)) != TCL_OK) + goto err; + if (CDB_LOCKING(env)) { + myobj = NewStringObj("-cdb", strlen("-cdb")); + if ((result = Tcl_ListObjAppendElement(interp, + retlist, myobj)) != TCL_OK) + goto err; + } + if (CRYPTO_ON(env)) { + myobj = NewStringObj("-crypto", strlen("-crypto")); + if ((result = Tcl_ListObjAppendElement(interp, + retlist, myobj)) != TCL_OK) + goto err; + } + if (LOCKING_ON(env)) { + myobj = NewStringObj("-lock", strlen("-lock")); + if ((result = Tcl_ListObjAppendElement(interp, + retlist, myobj)) != TCL_OK) + goto err; + } + if (LOGGING_ON(env)) { + myobj = NewStringObj("-log", strlen("-log")); + if ((result = Tcl_ListObjAppendElement(interp, + retlist, myobj)) != TCL_OK) + goto err; + } + if (MPOOL_ON(env)) { + myobj = NewStringObj("-mpool", strlen("-mpool")); + if ((result = Tcl_ListObjAppendElement(interp, + retlist, myobj)) != TCL_OK) + goto err; + } + if (RPC_ON(dbenv)) { + myobj = NewStringObj("-rpc", strlen("-rpc")); + if ((result = Tcl_ListObjAppendElement(interp, + retlist, myobj)) != TCL_OK) + goto err; + } + if (REP_ON(env)) { + myobj = NewStringObj("-rep", strlen("-rep")); + if ((result = Tcl_ListObjAppendElement(interp, + retlist, myobj)) != TCL_OK) + goto err; + } + if (TXN_ON(env)) { + myobj = NewStringObj("-txn", strlen("-txn")); + if ((result = Tcl_ListObjAppendElement(interp, + retlist, myobj)) != TCL_OK) + goto err; + } + Tcl_SetObjResult(interp, retlist); +err: + return (result); +} + +/* + * tcl_EventNotify -- + * Call DB_ENV->set_event_notify(). + * + * PUBLIC: int tcl_EventNotify __P((Tcl_Interp *, DB_ENV *, Tcl_Obj *, + * PUBLIC: DBTCL_INFO *)); + * + * Note that this normally can/should be achieved as an argument to + * berkdb env, but we need to test changing the event function on + * the fly. + */ +int +tcl_EventNotify(interp, dbenv, eobj, ip) + Tcl_Interp *interp; /* Interpreter */ + DB_ENV *dbenv; + Tcl_Obj *eobj; /* The event proc */ + DBTCL_INFO *ip; +{ + int ret; + + /* + * We don't need to crack the event procedure out now. + */ + /* + * If we're replacing an existing event proc, decrement it now. + */ + if (ip->i_event != NULL) { + Tcl_DecrRefCount(ip->i_event); + } + ip->i_event = eobj; + Tcl_IncrRefCount(ip->i_event); + _debug_check(); + ret = dbenv->set_event_notify(dbenv, _EventFunc); + return (_ReturnSetup(interp, ret, DB_RETOK_STD(ret), "env event")); +} + +/* + * PUBLIC: int tcl_EnvSetFlags __P((Tcl_Interp *, DB_ENV *, Tcl_Obj *, + * PUBLIC: Tcl_Obj *)); + * + * tcl_EnvSetFlags -- + * Set flags in an env. + */ +int +tcl_EnvSetFlags(interp, dbenv, which, onoff) + Tcl_Interp *interp; /* Interpreter */ + DB_ENV *dbenv; /* Env pointer */ + Tcl_Obj *which; /* Which subsystem */ + Tcl_Obj *onoff; /* On or off */ +{ + static const char *sfwhich[] = { + "-auto_commit", + "-direct_db", + "-multiversion", + "-nolock", + "-nommap", + "-nopanic", + "-nosync", + "-overwrite", + "-panic", + "-wrnosync", + NULL + }; + enum sfwhich { + ENVSF_AUTOCOMMIT, + ENVSF_DIRECTDB, + ENVSF_MULTIVERSION, + ENVSF_NOLOCK, + ENVSF_NOMMAP, + ENVSF_NOPANIC, + ENVSF_NOSYNC, + ENVSF_OVERWRITE, + ENVSF_PANIC, + ENVSF_WRNOSYNC + }; + static const char *sfonoff[] = { + "off", + "on", + NULL + }; + enum sfonoff { + ENVSF_OFF, + ENVSF_ON + }; + int on, optindex, ret; + u_int32_t wh; + + if (Tcl_GetIndexFromObj(interp, which, sfwhich, "option", + TCL_EXACT, &optindex) != TCL_OK) + return (IS_HELP(which)); + + switch ((enum sfwhich)optindex) { + case ENVSF_AUTOCOMMIT: + wh = DB_AUTO_COMMIT; + break; + case ENVSF_DIRECTDB: + wh = DB_DIRECT_DB; + break; + case ENVSF_MULTIVERSION: + wh = DB_MULTIVERSION; + break; + case ENVSF_NOLOCK: + wh = DB_NOLOCKING; + break; + case ENVSF_NOMMAP: + wh = DB_NOMMAP; + break; + case ENVSF_NOSYNC: + wh = DB_TXN_NOSYNC; + break; + case ENVSF_NOPANIC: + wh = DB_NOPANIC; + break; + case ENVSF_PANIC: + wh = DB_PANIC_ENVIRONMENT; + break; + case ENVSF_OVERWRITE: + wh = DB_OVERWRITE; + break; + case ENVSF_WRNOSYNC: + wh = DB_TXN_WRITE_NOSYNC; + break; + default: + return (TCL_ERROR); + } + if (Tcl_GetIndexFromObj(interp, onoff, sfonoff, "option", + TCL_EXACT, &optindex) != TCL_OK) + return (IS_HELP(onoff)); + switch ((enum sfonoff)optindex) { + case ENVSF_OFF: + on = 0; + break; + case ENVSF_ON: + on = 1; + break; + default: + return (TCL_ERROR); + } + ret = dbenv->set_flags(dbenv, wh, on); + return (_ReturnSetup(interp, ret, DB_RETOK_STD(ret), + "env set flags")); +} + +/* + * tcl_EnvTest -- + * The "$env test ..." command is a sort of catch-all for any sort of + * desired test hook manipulation. The "abort", "check" and "copy" subcommands + * all set one or another certain location in the DB_ENV handle to a specific + * value. (In the case of "check", the value is an integer passed in with the + * command itself. For the other two, the "value" is a predefined enum + * constant, specified by name.) + * The "$env test force ..." subcommand invokes other, more arbitrary + * manipulations. + * Although these functions may not all seem closely related, putting them + * all under the name "test" has the aesthetic appeal of keeping the rest of the + * API clean. + * + * PUBLIC: int tcl_EnvTest __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB_ENV *)); + */ +int +tcl_EnvTest(interp, objc, objv, dbenv) + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ + DB_ENV *dbenv; /* Env pointer */ +{ + static const char *envtestcmd[] = { + "abort", + "check", + "copy", + "force", + NULL + }; + enum envtestcmd { + ENVTEST_ABORT, + ENVTEST_CHECK, + ENVTEST_COPY, + ENVTEST_FORCE + }; + static const char *envtestat[] = { + "electinit", + "electvote1", + "none", + "predestroy", + "preopen", + "postdestroy", + "postlog", + "postlogmeta", + "postopen", + "postsync", + "subdb_lock", + NULL + }; + enum envtestat { + ENVTEST_ELECTINIT, + ENVTEST_ELECTVOTE1, + ENVTEST_NONE, + ENVTEST_PREDESTROY, + ENVTEST_PREOPEN, + ENVTEST_POSTDESTROY, + ENVTEST_POSTLOG, + ENVTEST_POSTLOGMETA, + ENVTEST_POSTOPEN, + ENVTEST_POSTSYNC, + ENVTEST_SUBDB_LOCKS + }; + static const char *envtestforce[] = { + "noarchive_timeout", + NULL + }; + enum envtestforce { + ENVTEST_NOARCHIVE_TIMEOUT + }; + ENV *env; + int *loc, optindex, result, testval; + + env = dbenv->env; + result = TCL_OK; + loc = NULL; + + if (objc != 4) { + Tcl_WrongNumArgs(interp, + 2, objv, "abort|check|copy|force <args>"); + return (TCL_ERROR); + } + + /* + * This must be the "check", "copy" or "abort" portion of the command. + */ + if (Tcl_GetIndexFromObj(interp, objv[2], envtestcmd, "command", + TCL_EXACT, &optindex) != TCL_OK) { + result = IS_HELP(objv[2]); + return (result); + } + switch ((enum envtestcmd)optindex) { + case ENVTEST_ABORT: + loc = &env->test_abort; + break; + case ENVTEST_CHECK: + loc = &env->test_check; + if (Tcl_GetIntFromObj(interp, objv[3], &testval) != TCL_OK) { + result = IS_HELP(objv[3]); + return (result); + } + goto done; + case ENVTEST_COPY: + loc = &env->test_copy; + break; + case ENVTEST_FORCE: + if (Tcl_GetIndexFromObj(interp, objv[3], envtestforce, "arg", + TCL_EXACT, &optindex) != TCL_OK) { + result = IS_HELP(objv[3]); + return (result); + } + /* + * In the future we might add more, and then we'd use a switch + * statement. + */ + DB_ASSERT(env, + (enum envtestforce)optindex == ENVTEST_NOARCHIVE_TIMEOUT); + return (tcl_RepNoarchiveTimeout(interp, dbenv)); + default: + Tcl_SetResult(interp, "Illegal store location", TCL_STATIC); + return (TCL_ERROR); + } + + /* + * This must be the location portion of the command. + */ + if (Tcl_GetIndexFromObj(interp, objv[3], envtestat, "location", + TCL_EXACT, &optindex) != TCL_OK) { + result = IS_HELP(objv[3]); + return (result); + } + switch ((enum envtestat)optindex) { + case ENVTEST_ELECTINIT: + DB_ASSERT(env, loc == &env->test_abort); + testval = DB_TEST_ELECTINIT; + break; + case ENVTEST_ELECTVOTE1: + DB_ASSERT(env, loc == &env->test_abort); + testval = DB_TEST_ELECTVOTE1; + break; + case ENVTEST_NONE: + testval = 0; + break; + case ENVTEST_PREOPEN: + testval = DB_TEST_PREOPEN; + break; + case ENVTEST_PREDESTROY: + testval = DB_TEST_PREDESTROY; + break; + case ENVTEST_POSTLOG: + testval = DB_TEST_POSTLOG; + break; + case ENVTEST_POSTLOGMETA: + testval = DB_TEST_POSTLOGMETA; + break; + case ENVTEST_POSTOPEN: + testval = DB_TEST_POSTOPEN; + break; + case ENVTEST_POSTDESTROY: + testval = DB_TEST_POSTDESTROY; + break; + case ENVTEST_POSTSYNC: + testval = DB_TEST_POSTSYNC; + break; + case ENVTEST_SUBDB_LOCKS: + DB_ASSERT(env, loc == &env->test_abort); + testval = DB_TEST_SUBDB_LOCKS; + break; + default: + Tcl_SetResult(interp, "Illegal test location", TCL_STATIC); + return (TCL_ERROR); + } +done: + *loc = testval; + Tcl_SetResult(interp, "0", TCL_STATIC); + return (result); +} +#endif + +/* + * env_DbRemove -- + * Implements the ENV->dbremove command. + */ +static int +env_DbRemove(interp, objc, objv, dbenv) + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ + DB_ENV *dbenv; +{ + static const char *envdbrem[] = { + "-auto_commit", + "-notdurable", + "-txn", + "--", + NULL + }; + enum envdbrem { + TCL_EDBREM_COMMIT, + TCL_EDBREM_NOTDURABLE, + TCL_EDBREM_TXN, + TCL_EDBREM_ENDARG + }; + DB_TXN *txn; + u_int32_t flag; + int endarg, i, optindex, result, ret, subdblen; + u_char *subdbtmp; + char *arg, *db, *subdb, msg[MSG_SIZE]; + + txn = NULL; + result = TCL_OK; + subdbtmp = NULL; + db = subdb = NULL; + endarg = 0; + flag = 0; + + if (objc < 2) { + Tcl_WrongNumArgs(interp, 2, objv, "?args? filename ?database?"); + return (TCL_ERROR); + } + + /* + * We must first parse for the environment flag, since that + * is needed for db_create. Then create the db handle. + */ + i = 2; + while (i < objc) { + if (Tcl_GetIndexFromObj(interp, objv[i], envdbrem, + "option", TCL_EXACT, &optindex) != TCL_OK) { + arg = Tcl_GetStringFromObj(objv[i], NULL); + if (arg[0] == '-') { + result = IS_HELP(objv[i]); + goto error; + } else + Tcl_ResetResult(interp); + break; + } + i++; + switch ((enum envdbrem)optindex) { + case TCL_EDBREM_COMMIT: + flag |= DB_AUTO_COMMIT; + break; + case TCL_EDBREM_TXN: + if (i >= objc) { + Tcl_WrongNumArgs(interp, 2, objv, "?-txn id?"); + result = TCL_ERROR; + break; + } + arg = Tcl_GetStringFromObj(objv[i++], NULL); + txn = NAME_TO_TXN(arg); + if (txn == NULL) { + snprintf(msg, MSG_SIZE, + "env dbremove: Invalid txn %s\n", arg); + Tcl_SetResult(interp, msg, TCL_VOLATILE); + return (TCL_ERROR); + } + break; + case TCL_EDBREM_ENDARG: + endarg = 1; + break; + case TCL_EDBREM_NOTDURABLE: + flag |= DB_TXN_NOT_DURABLE; + break; + } + /* + * If, at any time, parsing the args we get an error, + * bail out and return. + */ + if (result != TCL_OK) + goto error; + if (endarg) + break; + } + if (result != TCL_OK) + goto error; + /* + * Any args we have left, (better be 1 or 2 left) are + * file names. If there is 1, a db name, if 2 a db and subdb name. + */ + if ((i != (objc - 1)) || (i != (objc - 2))) { + /* + * Dbs must be NULL terminated file names, but subdbs can + * be anything. Use Strings for the db name and byte + * arrays for the subdb. + */ + db = Tcl_GetStringFromObj(objv[i++], NULL); + if (strcmp(db, "") == 0) + db = NULL; + if (i != objc) { + subdbtmp = + Tcl_GetByteArrayFromObj(objv[i++], &subdblen); + if ((ret = __os_malloc( + dbenv->env, (size_t)subdblen + 1, &subdb)) != 0) { + Tcl_SetResult(interp, + db_strerror(ret), TCL_STATIC); + return (0); + } + memcpy(subdb, subdbtmp, (size_t)subdblen); + subdb[subdblen] = '\0'; + } + } else { + Tcl_WrongNumArgs(interp, 2, objv, "?args? filename ?database?"); + result = TCL_ERROR; + goto error; + } + ret = dbenv->dbremove(dbenv, txn, db, subdb, flag); + result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), + "env dbremove"); +error: + if (subdb) + __os_free(dbenv->env, subdb); + return (result); +} + +/* + * env_DbRename -- + * Implements the ENV->dbrename command. + */ +static int +env_DbRename(interp, objc, objv, dbenv) + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ + DB_ENV *dbenv; +{ + static const char *envdbmv[] = { + "-auto_commit", + "-txn", + "--", + NULL + }; + enum envdbmv { + TCL_EDBMV_COMMIT, + TCL_EDBMV_TXN, + TCL_EDBMV_ENDARG + }; + DB_TXN *txn; + u_int32_t flag; + int endarg, i, newlen, optindex, result, ret, subdblen; + u_char *subdbtmp; + char *arg, *db, *newname, *subdb, msg[MSG_SIZE]; + + txn = NULL; + result = TCL_OK; + subdbtmp = NULL; + db = newname = subdb = NULL; + endarg = 0; + flag = 0; + + if (objc < 2) { + Tcl_WrongNumArgs(interp, 3, objv, + "?args? filename ?database? ?newname?"); + return (TCL_ERROR); + } + + /* + * We must first parse for the environment flag, since that + * is needed for db_create. Then create the db handle. + */ + i = 2; + while (i < objc) { + if (Tcl_GetIndexFromObj(interp, objv[i], envdbmv, + "option", TCL_EXACT, &optindex) != TCL_OK) { + arg = Tcl_GetStringFromObj(objv[i], NULL); + if (arg[0] == '-') { + result = IS_HELP(objv[i]); + goto error; + } else + Tcl_ResetResult(interp); + break; + } + i++; + switch ((enum envdbmv)optindex) { + case TCL_EDBMV_COMMIT: + flag |= DB_AUTO_COMMIT; + break; + case TCL_EDBMV_TXN: + if (i >= objc) { + Tcl_WrongNumArgs(interp, 2, objv, "?-txn id?"); + result = TCL_ERROR; + break; + } + arg = Tcl_GetStringFromObj(objv[i++], NULL); + txn = NAME_TO_TXN(arg); + if (txn == NULL) { + snprintf(msg, MSG_SIZE, + "env dbrename: Invalid txn %s\n", arg); + Tcl_SetResult(interp, msg, TCL_VOLATILE); + return (TCL_ERROR); + } + break; + case TCL_EDBMV_ENDARG: + endarg = 1; + break; + } + /* + * If, at any time, parsing the args we get an error, + * bail out and return. + */ + if (result != TCL_OK) + goto error; + if (endarg) + break; + } + if (result != TCL_OK) + goto error; + /* + * Any args we have left, (better be 2 or 3 left) are + * file names. If there is 2, a db name, if 3 a db and subdb name. + */ + if ((i != (objc - 2)) || (i != (objc - 3))) { + /* + * Dbs must be NULL terminated file names, but subdbs can + * be anything. Use Strings for the db name and byte + * arrays for the subdb. + */ + db = Tcl_GetStringFromObj(objv[i++], NULL); + if (strcmp(db, "") == 0) + db = NULL; + if (i == objc - 2) { + subdbtmp = + Tcl_GetByteArrayFromObj(objv[i++], &subdblen); + if ((ret = __os_malloc( + dbenv->env, (size_t)subdblen + 1, &subdb)) != 0) { + Tcl_SetResult(interp, + db_strerror(ret), TCL_STATIC); + return (0); + } + memcpy(subdb, subdbtmp, (size_t)subdblen); + subdb[subdblen] = '\0'; + } + subdbtmp = Tcl_GetByteArrayFromObj(objv[i++], &newlen); + if ((ret = __os_malloc( + dbenv->env, (size_t)newlen + 1, &newname)) != 0) { + Tcl_SetResult(interp, + db_strerror(ret), TCL_STATIC); + return (0); + } + memcpy(newname, subdbtmp, (size_t)newlen); + newname[newlen] = '\0'; + } else { + Tcl_WrongNumArgs(interp, 3, objv, + "?args? filename ?database? ?newname?"); + result = TCL_ERROR; + goto error; + } + ret = dbenv->dbrename(dbenv, txn, db, subdb, newname, flag); + result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), + "env dbrename"); +error: + if (subdb) + __os_free(dbenv->env, subdb); + if (newname) + __os_free(dbenv->env, newname); + return (result); +} + +/* + * env_GetFlags -- + * Implements the ENV->get_flags command. + */ +static int +env_GetFlags(interp, objc, objv, dbenv) + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ + DB_ENV *dbenv; +{ + int i, ret, result; + u_int32_t flags; + char buf[512]; + Tcl_Obj *res; + + static const struct { + u_int32_t flag; + char *arg; + } open_flags[] = { + { DB_AUTO_COMMIT, "-auto_commit" }, + { DB_CDB_ALLDB, "-cdb_alldb" }, + { DB_DIRECT_DB, "-direct_db" }, + { DB_MULTIVERSION, "-multiversion" }, + { DB_NOLOCKING, "-nolock" }, + { DB_NOMMAP, "-nommap" }, + { DB_NOPANIC, "-nopanic" }, + { DB_OVERWRITE, "-overwrite" }, + { DB_PANIC_ENVIRONMENT, "-panic" }, + { DB_REGION_INIT, "-region_init" }, + { DB_TXN_NOSYNC, "-nosync" }, + { DB_TXN_WRITE_NOSYNC, "-wrnosync" }, + { DB_YIELDCPU, "-yield" }, + { 0, NULL } + }; + + if (objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, NULL); + return (TCL_ERROR); + } + + ret = dbenv->get_flags(dbenv, &flags); + if ((result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), + "env get_flags")) == TCL_OK) { + buf[0] = '\0'; + + for (i = 0; open_flags[i].flag != 0; i++) + if (LF_ISSET(open_flags[i].flag)) { + if (strlen(buf) > 0) + (void)strncat(buf, " ", sizeof(buf)); + (void)strncat( + buf, open_flags[i].arg, sizeof(buf)); + } + + res = NewStringObj(buf, strlen(buf)); + Tcl_SetObjResult(interp, res); + } + + return (result); +} + +/* + * env_GetOpenFlag -- + * Implements the ENV->get_open_flags command. + */ +static int +env_GetOpenFlag(interp, objc, objv, dbenv) + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ + DB_ENV *dbenv; +{ + int i, ret, result; + u_int32_t flags; + char buf[512]; + Tcl_Obj *res; + + static const struct { + u_int32_t flag; + char *arg; + } open_flags[] = { + { DB_CREATE, "-create" }, + { DB_FAILCHK, "-failchk" }, + { DB_INIT_CDB, "-cdb" }, + { DB_INIT_LOCK, "-lock" }, + { DB_INIT_LOG, "-log" }, + { DB_INIT_MPOOL, "-mpool" }, + { DB_INIT_REP, "-rep" }, + { DB_INIT_TXN, "-txn" }, + { DB_LOCKDOWN, "-lockdown" }, + { DB_PRIVATE, "-private" }, + { DB_RECOVER, "-recover" }, + { DB_RECOVER_FATAL, "-recover_fatal" }, + { DB_REGISTER, "-register" }, + { DB_FAILCHK, "-failchk" }, + { DB_SYSTEM_MEM, "-system_mem" }, + { DB_THREAD, "-thread" }, + { DB_USE_ENVIRON, "-use_environ" }, + { DB_USE_ENVIRON_ROOT, "-use_environ_root" }, + { 0, NULL } + }; + + if (objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, NULL); + return (TCL_ERROR); + } + + ret = dbenv->get_open_flags(dbenv, &flags); + if ((result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), + "env get_open_flags")) == TCL_OK) { + buf[0] = '\0'; + + for (i = 0; open_flags[i].flag != 0; i++) + if (LF_ISSET(open_flags[i].flag)) { + if (strlen(buf) > 0) + (void)strncat(buf, " ", sizeof(buf)); + (void)strncat( + buf, open_flags[i].arg, sizeof(buf)); + } + + res = NewStringObj(buf, strlen(buf)); + Tcl_SetObjResult(interp, res); + } + + return (result); +} + +/* + * PUBLIC: int tcl_EnvGetEncryptFlags __P((Tcl_Interp *, int, Tcl_Obj * CONST*, + * PUBLIC: DB_ENV *)); + * + * tcl_EnvGetEncryptFlags -- + * Implements the ENV->get_encrypt_flags command. + */ +int +tcl_EnvGetEncryptFlags(interp, objc, objv, dbenv) + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ + DB_ENV *dbenv; /* Database pointer */ +{ + int i, ret, result; + u_int32_t flags; + char buf[512]; + Tcl_Obj *res; + + static const struct { + u_int32_t flag; + char *arg; + } encrypt_flags[] = { + { DB_ENCRYPT_AES, "-encryptaes" }, + { 0, NULL } + }; + + if (objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, NULL); + return (TCL_ERROR); + } + + ret = dbenv->get_encrypt_flags(dbenv, &flags); + if ((result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), + "env get_encrypt_flags")) == TCL_OK) { + buf[0] = '\0'; + + for (i = 0; encrypt_flags[i].flag != 0; i++) + if (LF_ISSET(encrypt_flags[i].flag)) { + if (strlen(buf) > 0) + (void)strncat(buf, " ", sizeof(buf)); + (void)strncat( + buf, encrypt_flags[i].arg, sizeof(buf)); + } + + res = NewStringObj(buf, strlen(buf)); + Tcl_SetObjResult(interp, res); + } + + return (result); +} + +/* + * env_GetLockDetect -- + * Implements the ENV->get_lk_detect command. + */ +static int +env_GetLockDetect(interp, objc, objv, dbenv) + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ + DB_ENV *dbenv; +{ + int i, ret, result; + u_int32_t lk_detect; + const char *answer; + Tcl_Obj *res; + static const struct { + u_int32_t flag; + char *name; + } lk_detect_returns[] = { + { DB_LOCK_DEFAULT, "default" }, + { DB_LOCK_EXPIRE, "expire" }, + { DB_LOCK_MAXLOCKS, "maxlocks" }, + { DB_LOCK_MAXWRITE, "maxwrite" }, + { DB_LOCK_MINLOCKS, "minlocks" }, + { DB_LOCK_MINWRITE, "minwrite" }, + { DB_LOCK_OLDEST, "oldest" }, + { DB_LOCK_RANDOM, "random" }, + { DB_LOCK_YOUNGEST, "youngest" }, + { 0, NULL } + }; + + if (objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, NULL); + return (TCL_ERROR); + } + ret = dbenv->get_lk_detect(dbenv, &lk_detect); + if ((result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), + "env get_lk_detect")) == TCL_OK) { + answer = "unknown"; + for (i = 0; lk_detect_returns[i].flag != 0; i++) + if (lk_detect == lk_detect_returns[i].flag) + answer = lk_detect_returns[i].name; + + res = NewStringObj(answer, strlen(answer)); + Tcl_SetObjResult(interp, res); + } + + return (result); +} + +/* + * env_GetTimeout -- + * Implements the ENV->get_timeout command. + */ +static int +env_GetTimeout(interp, objc, objv, dbenv) + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ + DB_ENV *dbenv; +{ + static const struct { + u_int32_t flag; + char *arg; + } timeout_flags[] = { + { DB_SET_LOCK_TIMEOUT, "lock" }, + { DB_SET_REG_TIMEOUT, "reg" }, + { DB_SET_TXN_TIMEOUT, "txn" }, + { 0, NULL } + }; + Tcl_Obj *res; + db_timeout_t timeout; + u_int32_t which; + int i, ret, result; + const char *arg; + + COMPQUIET(timeout, 0); + + if (objc != 3) { + Tcl_WrongNumArgs(interp, 1, objv, NULL); + return (TCL_ERROR); + } + + arg = Tcl_GetStringFromObj(objv[2], NULL); + which = 0; + for (i = 0; timeout_flags[i].flag != 0; i++) + if (strcmp(arg, timeout_flags[i].arg) == 0) + which = timeout_flags[i].flag; + if (which == 0) { + ret = EINVAL; + goto err; + } + + ret = dbenv->get_timeout(dbenv, &timeout, which); +err: if ((result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), + "env get_timeout")) == TCL_OK) { + res = Tcl_NewLongObj((long)timeout); + Tcl_SetObjResult(interp, res); + } + + return (result); +} + +/* + * env_GetVerbose -- + * Implements the ENV->get_open_flags command. + */ +static int +env_GetVerbose(interp, objc, objv, dbenv) + Tcl_Interp *interp; /* Interpreter */ + int objc; /* How many arguments? */ + Tcl_Obj *CONST objv[]; /* The argument objects */ + DB_ENV *dbenv; +{ + static const struct { + u_int32_t flag; + char *arg; + } verbose_flags[] = { + { DB_VERB_DEADLOCK, "deadlock" }, + { DB_VERB_FILEOPS, "fileops" }, + { DB_VERB_FILEOPS_ALL, "fileops_all" }, + { DB_VERB_RECOVERY, "recovery" }, + { DB_VERB_REGISTER, "register" }, + { DB_VERB_REPLICATION, "rep" }, + { DB_VERB_REP_ELECT, "rep_elect" }, + { DB_VERB_REP_LEASE, "rep_lease" }, + { DB_VERB_REP_MISC, "rep_misc" }, + { DB_VERB_REP_MSGS, "rep_msgs" }, + { DB_VERB_REP_SYNC, "rep_sync" }, + { DB_VERB_REP_TEST, "rep_test" }, + { DB_VERB_REPMGR_CONNFAIL, "repmgr_connfail" }, + { DB_VERB_REPMGR_MISC, "repmgr_misc" }, + { DB_VERB_WAITSFOR, "wait" }, + { 0, NULL } + }; + Tcl_Obj *res; + u_int32_t which; + int i, onoff, ret, result; + const char *arg, *answer; + + COMPQUIET(onoff, 0); + + if (objc != 3) { + Tcl_WrongNumArgs(interp, 1, objv, NULL); + return (TCL_ERROR); + } + + arg = Tcl_GetStringFromObj(objv[2], NULL); + which = 0; + for (i = 0; verbose_flags[i].flag != 0; i++) + if (strcmp(arg, verbose_flags[i].arg) == 0) + which = verbose_flags[i].flag; + if (which == 0) { + ret = EINVAL; + goto err; + } + + ret = dbenv->get_verbose(dbenv, which, &onoff); +err: if ((result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), + "env get_verbose")) == 0) { + answer = onoff ? "on" : "off"; + res = NewStringObj(answer, strlen(answer)); + Tcl_SetObjResult(interp, res); + } + + return (result); +} + +/* + * PUBLIC: void tcl_EnvSetErrfile __P((Tcl_Interp *, DB_ENV *, DBTCL_INFO *, + * PUBLIC: char *)); + * + * tcl_EnvSetErrfile -- + * Implements the ENV->set_errfile command. + */ +void +tcl_EnvSetErrfile(interp, dbenv, ip, errf) + Tcl_Interp *interp; /* Interpreter */ + DB_ENV *dbenv; /* Database pointer */ + DBTCL_INFO *ip; /* Our internal info */ + char *errf; +{ + COMPQUIET(interp, NULL); + /* + * If the user already set one, free it. + */ + if (ip->i_err != NULL && ip->i_err != stdout && + ip->i_err != stderr) + (void)fclose(ip->i_err); + if (strcmp(errf, "/dev/stdout") == 0) + ip->i_err = stdout; + else if (strcmp(errf, "/dev/stderr") == 0) + ip->i_err = stderr; + else + ip->i_err = fopen(errf, "a"); + if (ip->i_err != NULL) + dbenv->set_errfile(dbenv, ip->i_err); +} + +/* + * PUBLIC: int tcl_EnvSetErrpfx __P((Tcl_Interp *, DB_ENV *, DBTCL_INFO *, + * PUBLIC: char *)); + * + * tcl_EnvSetErrpfx -- + * Implements the ENV->set_errpfx command. + */ +int +tcl_EnvSetErrpfx(interp, dbenv, ip, pfx) + Tcl_Interp *interp; /* Interpreter */ + DB_ENV *dbenv; /* Database pointer */ + DBTCL_INFO *ip; /* Our internal info */ + char *pfx; +{ + int result, ret; + + /* + * Assume success. The only thing that can fail is + * the __os_strdup. + */ + result = TCL_OK; + Tcl_SetResult(interp, "0", TCL_STATIC); + /* + * If the user already set one, free it. + */ + if (ip->i_errpfx != NULL) + __os_free(dbenv->env, ip->i_errpfx); + if ((ret = __os_strdup(dbenv->env, pfx, &ip->i_errpfx)) != 0) { + result = _ReturnSetup(interp, ret, + DB_RETOK_STD(ret), "__os_strdup"); + ip->i_errpfx = NULL; + } + if (ip->i_errpfx != NULL) + dbenv->set_errpfx(dbenv, ip->i_errpfx); + return (result); +} |