1/*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 1999-2009 Oracle.  All rights reserved.
5 *
6 * $Id$
7 */
8
9#include "db_config.h"
10
11#include "db_int.h"
12#ifdef HAVE_SYSTEM_INCLUDE_FILES
13#include <tcl.h>
14#endif
15#include "dbinc/log.h"
16#include "dbinc/tcl_db.h"
17
18#ifdef CONFIG_TEST
19static int tcl_LogcGet __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB_LOGC *));
20
21/*
22 * tcl_LogArchive --
23 *
24 * PUBLIC: int tcl_LogArchive __P((Tcl_Interp *, int,
25 * PUBLIC:    Tcl_Obj * CONST*, DB_ENV *));
26 */
27int
28tcl_LogArchive(interp, objc, objv, dbenv)
29	Tcl_Interp *interp;		/* Interpreter */
30	int objc;			/* How many arguments? */
31	Tcl_Obj *CONST objv[];		/* The argument objects */
32	DB_ENV *dbenv;			/* Environment pointer */
33{
34	static const char *archopts[] = {
35		"-arch_abs",	"-arch_data",	"-arch_log",	"-arch_remove",
36		NULL
37	};
38	enum archopts {
39		ARCH_ABS,	ARCH_DATA,	ARCH_LOG,	ARCH_REMOVE
40	};
41	Tcl_Obj *fileobj, *res;
42	u_int32_t flag;
43	int i, optindex, result, ret;
44	char **file, **list;
45
46	result = TCL_OK;
47	flag = 0;
48	/*
49	 * Get the flag index from the object based on the options
50	 * defined above.
51	 */
52	i = 2;
53	while (i < objc) {
54		if (Tcl_GetIndexFromObj(interp, objv[i],
55		    archopts, "option", TCL_EXACT, &optindex) != TCL_OK)
56			return (IS_HELP(objv[i]));
57		i++;
58		switch ((enum archopts)optindex) {
59		case ARCH_ABS:
60			flag |= DB_ARCH_ABS;
61			break;
62		case ARCH_DATA:
63			flag |= DB_ARCH_DATA;
64			break;
65		case ARCH_LOG:
66			flag |= DB_ARCH_LOG;
67			break;
68		case ARCH_REMOVE:
69			flag |= DB_ARCH_REMOVE;
70			break;
71		}
72	}
73	_debug_check();
74	list = NULL;
75	ret = dbenv->log_archive(dbenv, &list, flag);
76	result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "log archive");
77	if (result == TCL_OK) {
78		res = Tcl_NewListObj(0, NULL);
79		for (file = list; file != NULL && *file != NULL; file++) {
80			fileobj = NewStringObj(*file, strlen(*file));
81			result = Tcl_ListObjAppendElement(interp, res, fileobj);
82			if (result != TCL_OK)
83				break;
84		}
85		Tcl_SetObjResult(interp, res);
86	}
87	if (list != NULL)
88		__os_ufree(dbenv->env, list);
89	return (result);
90}
91
92/*
93 * tcl_LogCompare --
94 *
95 * PUBLIC: int tcl_LogCompare __P((Tcl_Interp *, int,
96 * PUBLIC:    Tcl_Obj * CONST*));
97 */
98int
99tcl_LogCompare(interp, objc, objv)
100	Tcl_Interp *interp;		/* Interpreter */
101	int objc;			/* How many arguments? */
102	Tcl_Obj *CONST objv[];		/* The argument objects */
103{
104	DB_LSN lsn0, lsn1;
105	Tcl_Obj *res;
106	int result, ret;
107
108	result = TCL_OK;
109	/*
110	 * No flags, must be 4 args.
111	 */
112	if (objc != 4) {
113		Tcl_WrongNumArgs(interp, 2, objv, "lsn1 lsn2");
114		return (TCL_ERROR);
115	}
116
117	result = _GetLsn(interp, objv[2], &lsn0);
118	if (result == TCL_ERROR)
119		return (result);
120	result = _GetLsn(interp, objv[3], &lsn1);
121	if (result == TCL_ERROR)
122		return (result);
123
124	_debug_check();
125	ret = log_compare(&lsn0, &lsn1);
126	res = Tcl_NewIntObj(ret);
127	Tcl_SetObjResult(interp, res);
128	return (result);
129}
130
131/*
132 * tcl_LogFile --
133 *
134 * PUBLIC: int tcl_LogFile __P((Tcl_Interp *, int,
135 * PUBLIC:    Tcl_Obj * CONST*, DB_ENV *));
136 */
137int
138tcl_LogFile(interp, objc, objv, dbenv)
139	Tcl_Interp *interp;		/* Interpreter */
140	int objc;			/* How many arguments? */
141	Tcl_Obj *CONST objv[];		/* The argument objects */
142	DB_ENV *dbenv;			/* Environment pointer */
143{
144	DB_LSN lsn;
145	Tcl_Obj *res;
146	size_t len;
147	int result, ret;
148	char *name;
149
150	result = TCL_OK;
151	/*
152	 * No flags, must be 3 args.
153	 */
154	if (objc != 3) {
155		Tcl_WrongNumArgs(interp, 2, objv, "lsn");
156		return (TCL_ERROR);
157	}
158
159	result = _GetLsn(interp, objv[2], &lsn);
160	if (result == TCL_ERROR)
161		return (result);
162
163	len = MSG_SIZE;
164	ret = ENOMEM;
165	name = NULL;
166	while (ret == ENOMEM) {
167		if (name != NULL)
168			__os_free(dbenv->env, name);
169		ret = __os_malloc(dbenv->env, len, &name);
170		if (ret != 0) {
171			Tcl_SetResult(interp, db_strerror(ret), TCL_STATIC);
172			break;
173		}
174		_debug_check();
175		ret = dbenv->log_file(dbenv, &lsn, name, len);
176		len *= 2;
177	}
178	result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "log_file");
179	if (ret == 0) {
180		res = NewStringObj(name, strlen(name));
181		Tcl_SetObjResult(interp, res);
182	}
183
184	if (name != NULL)
185		__os_free(dbenv->env, name);
186
187	return (result);
188}
189
190/*
191 * tcl_LogFlush --
192 *
193 * PUBLIC: int tcl_LogFlush __P((Tcl_Interp *, int,
194 * PUBLIC:    Tcl_Obj * CONST*, DB_ENV *));
195 */
196int
197tcl_LogFlush(interp, objc, objv, dbenv)
198	Tcl_Interp *interp;		/* Interpreter */
199	int objc;			/* How many arguments? */
200	Tcl_Obj *CONST objv[];		/* The argument objects */
201	DB_ENV *dbenv;			/* Environment pointer */
202{
203	DB_LSN lsn, *lsnp;
204	int result, ret;
205
206	result = TCL_OK;
207	/*
208	 * No flags, must be 2 or 3 args.
209	 */
210	if (objc > 3) {
211		Tcl_WrongNumArgs(interp, 2, objv, "?lsn?");
212		return (TCL_ERROR);
213	}
214
215	if (objc == 3) {
216		lsnp = &lsn;
217		result = _GetLsn(interp, objv[2], &lsn);
218		if (result == TCL_ERROR)
219			return (result);
220	} else
221		lsnp = NULL;
222
223	_debug_check();
224	ret = dbenv->log_flush(dbenv, lsnp);
225	result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "log_flush");
226	return (result);
227}
228
229/*
230 * tcl_LogGet --
231 *
232 * PUBLIC: int tcl_LogGet __P((Tcl_Interp *, int,
233 * PUBLIC:    Tcl_Obj * CONST*, DB_ENV *));
234 */
235int
236tcl_LogGet(interp, objc, objv, dbenv)
237	Tcl_Interp *interp;		/* Interpreter */
238	int objc;			/* How many arguments? */
239	Tcl_Obj *CONST objv[];		/* The argument objects */
240	DB_ENV *dbenv;			/* Environment pointer */
241{
242
243	COMPQUIET(objv, NULL);
244	COMPQUIET(objc, 0);
245	COMPQUIET(dbenv, NULL);
246
247	Tcl_SetResult(interp, "FAIL: log_get deprecated\n", TCL_STATIC);
248	return (TCL_ERROR);
249}
250
251/*
252 * tcl_LogPut --
253 *
254 * PUBLIC: int tcl_LogPut __P((Tcl_Interp *, int,
255 * PUBLIC:    Tcl_Obj * CONST*, DB_ENV *));
256 */
257int
258tcl_LogPut(interp, objc, objv, dbenv)
259	Tcl_Interp *interp;		/* Interpreter */
260	int objc;			/* How many arguments? */
261	Tcl_Obj *CONST objv[];		/* The argument objects */
262	DB_ENV *dbenv;			/* Environment pointer */
263{
264	static const char *logputopts[] = {
265		"-flush",
266		NULL
267	};
268	enum logputopts {
269		LOGPUT_FLUSH
270	};
271	DB_LSN lsn;
272	DBT data;
273	Tcl_Obj *intobj, *res;
274	void *dtmp;
275	u_int32_t flag;
276	int freedata, optindex, result, ret;
277
278	result = TCL_OK;
279	flag = 0;
280	freedata = 0;
281	if (objc < 3) {
282		Tcl_WrongNumArgs(interp, 2, objv, "?-args? record");
283		return (TCL_ERROR);
284	}
285
286	/*
287	 * Data/record must be the last arg.
288	 */
289	memset(&data, 0, sizeof(data));
290	ret = _CopyObjBytes(interp, objv[objc-1], &dtmp,
291	    &data.size, &freedata);
292	if (ret != 0) {
293		result = _ReturnSetup(interp, ret,
294		    DB_RETOK_STD(ret), "log put");
295		return (result);
296	}
297	data.data = dtmp;
298
299	/*
300	 * Get the command name index from the object based on the options
301	 * defined above.
302	 */
303	if (objc == 4) {
304		if (Tcl_GetIndexFromObj(interp, objv[2],
305		    logputopts, "option", TCL_EXACT, &optindex) != TCL_OK) {
306			return (IS_HELP(objv[2]));
307		}
308		switch ((enum logputopts)optindex) {
309		case LOGPUT_FLUSH:
310			flag = DB_FLUSH;
311			break;
312		}
313	}
314
315	if (result == TCL_ERROR)
316		return (result);
317
318	_debug_check();
319	ret = dbenv->log_put(dbenv, &lsn, &data, flag);
320	result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "log_put");
321	if (result == TCL_ERROR)
322		return (result);
323	res = Tcl_NewListObj(0, NULL);
324	intobj = Tcl_NewWideIntObj((Tcl_WideInt)lsn.file);
325	result = Tcl_ListObjAppendElement(interp, res, intobj);
326	intobj = Tcl_NewWideIntObj((Tcl_WideInt)lsn.offset);
327	result = Tcl_ListObjAppendElement(interp, res, intobj);
328	Tcl_SetObjResult(interp, res);
329	if (freedata)
330		__os_free(NULL, dtmp);
331	return (result);
332}
333/*
334 * tcl_LogStat --
335 *
336 * PUBLIC: int tcl_LogStat __P((Tcl_Interp *, int,
337 * PUBLIC:    Tcl_Obj * CONST*, DB_ENV *));
338 */
339int
340tcl_LogStat(interp, objc, objv, dbenv)
341	Tcl_Interp *interp;		/* Interpreter */
342	int objc;			/* How many arguments? */
343	Tcl_Obj *CONST objv[];		/* The argument objects */
344	DB_ENV *dbenv;			/* Environment pointer */
345{
346	DB_LOG_STAT *sp;
347	Tcl_Obj *res;
348	int result, ret;
349
350	result = TCL_OK;
351	/*
352	 * No args for this.  Error if there are some.
353	 */
354	if (objc != 2) {
355		Tcl_WrongNumArgs(interp, 2, objv, NULL);
356		return (TCL_ERROR);
357	}
358	_debug_check();
359	ret = dbenv->log_stat(dbenv, &sp, 0);
360	result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "log stat");
361	if (result == TCL_ERROR)
362		return (result);
363
364	/*
365	 * Have our stats, now construct the name value
366	 * list pairs and free up the memory.
367	 */
368	res = Tcl_NewObj();
369	/*
370	 * MAKE_STAT_LIST assumes 'res' and 'error' label.
371	 */
372#ifdef HAVE_STATISTICS
373	MAKE_STAT_LIST("Magic", sp->st_magic);
374	MAKE_STAT_LIST("Log file Version", sp->st_version);
375	MAKE_STAT_LIST("Region size", sp->st_regsize);
376	MAKE_STAT_LIST("Log file mode", sp->st_mode);
377	MAKE_STAT_LIST("Log record cache size", sp->st_lg_bsize);
378	MAKE_STAT_LIST("Current log file size", sp->st_lg_size);
379	MAKE_WSTAT_LIST("Log file records written", sp->st_record);
380	MAKE_STAT_LIST("Mbytes written", sp->st_w_mbytes);
381	MAKE_STAT_LIST("Bytes written (over Mb)", sp->st_w_bytes);
382	MAKE_STAT_LIST("Mbytes written since checkpoint", sp->st_wc_mbytes);
383	MAKE_STAT_LIST("Bytes written (over Mb) since checkpoint",
384	    sp->st_wc_bytes);
385	MAKE_WSTAT_LIST("Times log written", sp->st_wcount);
386	MAKE_STAT_LIST("Times log written because cache filled up",
387	    sp->st_wcount_fill);
388	MAKE_WSTAT_LIST("Times log read from disk", sp->st_rcount);
389	MAKE_WSTAT_LIST("Times log flushed to disk", sp->st_scount);
390	MAKE_STAT_LIST("Current log file number", sp->st_cur_file);
391	MAKE_STAT_LIST("Current log file offset", sp->st_cur_offset);
392	MAKE_STAT_LIST("On-disk log file number", sp->st_disk_file);
393	MAKE_STAT_LIST("On-disk log file offset", sp->st_disk_offset);
394	MAKE_STAT_LIST("Max commits in a log flush", sp->st_maxcommitperflush);
395	MAKE_STAT_LIST("Min commits in a log flush", sp->st_mincommitperflush);
396	MAKE_WSTAT_LIST("Number of region lock waits", sp->st_region_wait);
397	MAKE_WSTAT_LIST("Number of region lock nowaits", sp->st_region_nowait);
398#endif
399	Tcl_SetObjResult(interp, res);
400error:
401	__os_ufree(dbenv->env, sp);
402	return (result);
403}
404
405/*
406 * logc_Cmd --
407 *	Implements the log cursor command.
408 *
409 * PUBLIC: int logc_Cmd __P((ClientData, Tcl_Interp *, int, Tcl_Obj * CONST*));
410 */
411int
412logc_Cmd(clientData, interp, objc, objv)
413	ClientData clientData;		/* Cursor handle */
414	Tcl_Interp *interp;		/* Interpreter */
415	int objc;			/* How many arguments? */
416	Tcl_Obj *CONST objv[];		/* The argument objects */
417{
418	static const char *logccmds[] = {
419		"close",
420		"get",
421		"version",
422		NULL
423	};
424	enum logccmds {
425		LOGCCLOSE,
426		LOGCGET,
427		LOGCVERSION
428	};
429	DB_LOGC *logc;
430	DBTCL_INFO *logcip;
431	Tcl_Obj *res;
432	u_int32_t version;
433	int cmdindex, result, ret;
434
435	Tcl_ResetResult(interp);
436	logc = (DB_LOGC *)clientData;
437	logcip = _PtrToInfo((void *)logc);
438	result = TCL_OK;
439
440	if (objc <= 1) {
441		Tcl_WrongNumArgs(interp, 1, objv, "command cmdargs");
442		return (TCL_ERROR);
443	}
444	if (logc == NULL) {
445		Tcl_SetResult(interp, "NULL logc pointer", TCL_STATIC);
446		return (TCL_ERROR);
447	}
448	if (logcip == NULL) {
449		Tcl_SetResult(interp, "NULL logc info pointer", TCL_STATIC);
450		return (TCL_ERROR);
451	}
452
453	/*
454	 * Get the command name index from the object based on the berkdbcmds
455	 * defined above.
456	 */
457	if (Tcl_GetIndexFromObj(interp, objv[1], logccmds, "command",
458	    TCL_EXACT, &cmdindex) != TCL_OK)
459		return (IS_HELP(objv[1]));
460	switch ((enum logccmds)cmdindex) {
461	case LOGCCLOSE:
462		/*
463		 * No args for this.  Error if there are some.
464		 */
465		if (objc > 2) {
466			Tcl_WrongNumArgs(interp, 2, objv, NULL);
467			return (TCL_ERROR);
468		}
469		_debug_check();
470		ret = logc->close(logc, 0);
471		result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
472		    "logc close");
473		if (result == TCL_OK) {
474			(void)Tcl_DeleteCommand(interp, logcip->i_name);
475			_DeleteInfo(logcip);
476		}
477		break;
478	case LOGCGET:
479		result = tcl_LogcGet(interp, objc, objv, logc);
480		break;
481	case LOGCVERSION:
482		/*
483		 * No args for this.  Error if there are some.
484		 */
485		if (objc > 2) {
486			Tcl_WrongNumArgs(interp, 2, objv, NULL);
487			return (TCL_ERROR);
488		}
489		_debug_check();
490		ret = logc->version(logc, &version, 0);
491		if ((result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
492		    "logc version")) == TCL_OK) {
493			res = Tcl_NewIntObj((int)version);
494			Tcl_SetObjResult(interp, res);
495		}
496		break;
497	}
498
499	return (result);
500}
501
502static int
503tcl_LogcGet(interp, objc, objv, logc)
504	Tcl_Interp *interp;
505	int objc;
506	Tcl_Obj * CONST *objv;
507	DB_LOGC *logc;
508{
509	static const char *logcgetopts[] = {
510		"-current",
511		"-first",
512		"-last",
513		"-next",
514		"-prev",
515		"-set",
516		NULL
517	};
518	enum logcgetopts {
519		LOGCGET_CURRENT,
520		LOGCGET_FIRST,
521		LOGCGET_LAST,
522		LOGCGET_NEXT,
523		LOGCGET_PREV,
524		LOGCGET_SET
525	};
526	DB_LSN lsn;
527	DBT data;
528	Tcl_Obj *dataobj, *lsnlist, *myobjv[2], *res;
529	u_int32_t flag;
530	int i, myobjc, optindex, result, ret;
531
532	result = TCL_OK;
533	res = NULL;
534	flag = 0;
535
536	if (objc < 3) {
537		Tcl_WrongNumArgs(interp, 2, objv, "?-args? lsn");
538		return (TCL_ERROR);
539	}
540
541	/*
542	 * Get the command name index from the object based on the options
543	 * defined above.
544	 */
545	i = 2;
546	while (i < objc) {
547		if (Tcl_GetIndexFromObj(interp, objv[i],
548		    logcgetopts, "option", TCL_EXACT, &optindex) != TCL_OK)
549			return (IS_HELP(objv[i]));
550		i++;
551		switch ((enum logcgetopts)optindex) {
552		case LOGCGET_CURRENT:
553			FLAG_CHECK(flag);
554			flag |= DB_CURRENT;
555			break;
556		case LOGCGET_FIRST:
557			FLAG_CHECK(flag);
558			flag |= DB_FIRST;
559			break;
560		case LOGCGET_LAST:
561			FLAG_CHECK(flag);
562			flag |= DB_LAST;
563			break;
564		case LOGCGET_NEXT:
565			FLAG_CHECK(flag);
566			flag |= DB_NEXT;
567			break;
568		case LOGCGET_PREV:
569			FLAG_CHECK(flag);
570			flag |= DB_PREV;
571			break;
572		case LOGCGET_SET:
573			FLAG_CHECK(flag);
574			flag |= DB_SET;
575			if (i == objc) {
576				Tcl_WrongNumArgs(interp, 2, objv, "?-set lsn?");
577				result = TCL_ERROR;
578				break;
579			}
580			result = _GetLsn(interp, objv[i++], &lsn);
581			break;
582		}
583	}
584
585	if (result == TCL_ERROR)
586		return (result);
587
588	memset(&data, 0, sizeof(data));
589
590	_debug_check();
591	ret = logc->get(logc, &lsn, &data, flag);
592
593	res = Tcl_NewListObj(0, NULL);
594	if (res == NULL)
595		goto memerr;
596
597	if (ret == 0) {
598		/*
599		 * Success.  Set up return list as {LSN data} where LSN
600		 * is a sublist {file offset}.
601		 */
602		myobjc = 2;
603		myobjv[0] = Tcl_NewWideIntObj((Tcl_WideInt)lsn.file);
604		myobjv[1] = Tcl_NewWideIntObj((Tcl_WideInt)lsn.offset);
605		lsnlist = Tcl_NewListObj(myobjc, myobjv);
606		if (lsnlist == NULL)
607			goto memerr;
608
609		result = Tcl_ListObjAppendElement(interp, res, lsnlist);
610		dataobj = NewStringObj(data.data, data.size);
611		if (dataobj == NULL) {
612			goto memerr;
613		}
614		result = Tcl_ListObjAppendElement(interp, res, dataobj);
615	} else
616		result = _ReturnSetup(interp, ret, DB_RETOK_LGGET(ret),
617		    "DB_LOGC->get");
618
619	Tcl_SetObjResult(interp, res);
620
621	if (0) {
622memerr:		if (res != NULL) {
623			Tcl_DecrRefCount(res);
624		}
625		Tcl_SetResult(interp, "allocation failed", TCL_STATIC);
626	}
627
628	return (result);
629}
630
631static const char *confwhich[] = {
632	"autoremove",
633	"direct",
634	"dsync",
635	"inmemory",
636	"zero",
637	NULL
638};
639enum logwhich {
640	LOGCONF_AUTO,
641	LOGCONF_DIRECT,
642	LOGCONF_DSYNC,
643	LOGCONF_INMEMORY,
644	LOGCONF_ZERO
645};
646
647/*
648 * tcl_LogConfig --
649 *	Call DB_ENV->rep_set_config().
650 *
651 * PUBLIC: int tcl_LogConfig
652 * PUBLIC:     __P((Tcl_Interp *, DB_ENV *, Tcl_Obj *));
653 */
654int
655tcl_LogConfig(interp, dbenv, list)
656	Tcl_Interp *interp;		/* Interpreter */
657	DB_ENV *dbenv;			/* Environment pointer */
658	Tcl_Obj *list;			/* {which on|off} */
659{
660	static const char *confonoff[] = {
661		"off",
662		"on",
663		NULL
664	};
665	enum confonoff {
666		LOGCONF_OFF,
667		LOGCONF_ON
668	};
669	Tcl_Obj **myobjv, *onoff, *which;
670	int myobjc, on, optindex, result, ret;
671	u_int32_t wh;
672
673	result = Tcl_ListObjGetElements(interp, list, &myobjc, &myobjv);
674	if (myobjc != 2)
675		Tcl_WrongNumArgs(interp, 2, myobjv, "?{which onoff}?");
676	which = myobjv[0];
677	onoff = myobjv[1];
678	if (result != TCL_OK)
679		return (result);
680	if (Tcl_GetIndexFromObj(interp, which, confwhich, "option",
681	    TCL_EXACT, &optindex) != TCL_OK)
682		return (IS_HELP(which));
683
684	switch ((enum logwhich)optindex) {
685	case LOGCONF_AUTO:
686		wh = DB_LOG_AUTO_REMOVE;
687		break;
688	case LOGCONF_DIRECT:
689		wh = DB_LOG_DIRECT;
690		break;
691	case LOGCONF_DSYNC:
692		wh = DB_LOG_DSYNC;
693		break;
694	case LOGCONF_INMEMORY:
695		wh = DB_LOG_IN_MEMORY;
696		break;
697	case LOGCONF_ZERO:
698		wh = DB_LOG_ZERO;
699		break;
700	default:
701		return (TCL_ERROR);
702	}
703	if (Tcl_GetIndexFromObj(interp, onoff, confonoff, "option",
704	    TCL_EXACT, &optindex) != TCL_OK)
705		return (IS_HELP(onoff));
706	switch ((enum confonoff)optindex) {
707	case LOGCONF_OFF:
708		on = 0;
709		break;
710	case LOGCONF_ON:
711		on = 1;
712		break;
713	default:
714		return (TCL_ERROR);
715	}
716	ret = dbenv->log_set_config(dbenv, wh, on);
717	return (_ReturnSetup(interp, ret, DB_RETOK_STD(ret),
718	    "env rep_config"));
719}
720
721/*
722 * tcl_LogGetConfig --
723 *	Call DB_ENV->rep_get_config().
724 *
725 * PUBLIC: int tcl_LogGetConfig
726 * PUBLIC:     __P((Tcl_Interp *, DB_ENV *, Tcl_Obj *));
727 */
728int
729tcl_LogGetConfig(interp, dbenv, which)
730	Tcl_Interp *interp;		/* Interpreter */
731	DB_ENV *dbenv;			/* Environment pointer */
732	Tcl_Obj *which;			/* which flag */
733{
734	Tcl_Obj *res;
735	int on, optindex, result, ret;
736	u_int32_t wh;
737
738	if (Tcl_GetIndexFromObj(interp, which, confwhich, "option",
739	    TCL_EXACT, &optindex) != TCL_OK)
740		return (IS_HELP(which));
741
742	res = NULL;
743	switch ((enum logwhich)optindex) {
744	case LOGCONF_AUTO:
745		wh = DB_LOG_AUTO_REMOVE;
746		break;
747	case LOGCONF_DIRECT:
748		wh = DB_LOG_DIRECT;
749		break;
750	case LOGCONF_DSYNC:
751		wh = DB_LOG_DSYNC;
752		break;
753	case LOGCONF_INMEMORY:
754		wh = DB_LOG_IN_MEMORY;
755		break;
756	case LOGCONF_ZERO:
757		wh = DB_LOG_ZERO;
758		break;
759	default:
760		return (TCL_ERROR);
761	}
762	ret = dbenv->log_get_config(dbenv, wh, &on);
763	if ((result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
764	    "env log_config")) == TCL_OK) {
765		res = Tcl_NewIntObj(on);
766		Tcl_SetObjResult(interp, res);
767	}
768	return (result);
769}
770#endif
771