1 /*-
2  * See the file LICENSE for redistribution information.
3  *
4  * Copyright (c) 1999, 2013 Oracle and/or its affiliates.  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
19 static 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  */
27 int
tcl_LogArchive(interp,objc,objv,dbenv)28 tcl_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  */
98 int
tcl_LogCompare(interp,objc,objv)99 tcl_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  */
137 int
tcl_LogFile(interp,objc,objv,dbenv)138 tcl_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  */
196 int
tcl_LogFlush(interp,objc,objv,dbenv)197 tcl_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  */
235 int
tcl_LogGet(interp,objc,objv,dbenv)236 tcl_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  */
257 int
tcl_LogPut(interp,objc,objv,dbenv)258 tcl_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  */
339 int
tcl_LogStat(interp,objc,objv,dbenv)340 tcl_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_STAT_LIST("Initial fileid allocation", sp->st_fileid_init);
380 	MAKE_STAT_LIST("Current fileids in use", sp->st_nfileid);
381 	MAKE_STAT_LIST("Maximum fileids ever used", sp->st_maxnfileid);
382 	MAKE_WSTAT_LIST("Log file records written", sp->st_record);
383 	MAKE_STAT_LIST("Mbytes written", sp->st_w_mbytes);
384 	MAKE_STAT_LIST("Bytes written (over Mb)", sp->st_w_bytes);
385 	MAKE_STAT_LIST("Mbytes written since checkpoint", sp->st_wc_mbytes);
386 	MAKE_STAT_LIST("Bytes written (over Mb) since checkpoint",
387 	    sp->st_wc_bytes);
388 	MAKE_WSTAT_LIST("Times log written", sp->st_wcount);
389 	MAKE_STAT_LIST("Times log written because cache filled up",
390 	    sp->st_wcount_fill);
391 	MAKE_WSTAT_LIST("Times log read from disk", sp->st_rcount);
392 	MAKE_WSTAT_LIST("Times log flushed to disk", sp->st_scount);
393 	MAKE_STAT_LIST("Current log file number", sp->st_cur_file);
394 	MAKE_STAT_LIST("Current log file offset", sp->st_cur_offset);
395 	MAKE_STAT_LIST("On-disk log file number", sp->st_disk_file);
396 	MAKE_STAT_LIST("On-disk log file offset", sp->st_disk_offset);
397 	MAKE_STAT_LIST("Max commits in a log flush", sp->st_maxcommitperflush);
398 	MAKE_STAT_LIST("Min commits in a log flush", sp->st_mincommitperflush);
399 	MAKE_WSTAT_LIST("Number of region lock waits", sp->st_region_wait);
400 	MAKE_WSTAT_LIST("Number of region lock nowaits", sp->st_region_nowait);
401 #endif
402 	Tcl_SetObjResult(interp, res);
403 error:
404 	__os_ufree(dbenv->env, sp);
405 	return (result);
406 }
407 
408 /*
409  * tcl_LogStatPrint --
410  *
411  * PUBLIC: int tcl_LogStatPrint __P((Tcl_Interp *, int,
412  * PUBLIC:    Tcl_Obj * CONST*, DB_ENV *));
413  */
414 int
tcl_LogStatPrint(interp,objc,objv,dbenv)415 tcl_LogStatPrint(interp, objc, objv, dbenv)
416 	Tcl_Interp *interp;		/* Interpreter */
417 	int objc;			/* How many arguments? */
418 	Tcl_Obj *CONST objv[];		/* The argument objects */
419 	DB_ENV *dbenv;			/* Environment pointer */
420 {	static const char *logstatprtopts[] = {
421 		"-all",
422 		"-clear",
423 		 NULL
424 	};
425 	enum logstatprtopts {
426 		LOGSTATPRTALL,
427 		LOGSTATPRTCLEAR
428 	};
429 	u_int32_t flag;
430 	int i, optindex, result, ret;
431 
432 	result = TCL_OK;
433 	flag = 0;
434 	i = 2;
435 
436 	while (i < objc) {
437 		if (Tcl_GetIndexFromObj(interp, objv[i], logstatprtopts,
438 		    "option", TCL_EXACT, &optindex) != TCL_OK) {
439 			result = IS_HELP(objv[i]);
440 			goto error;
441 		}
442 		i++;
443 		switch ((enum logstatprtopts)optindex) {
444 		case LOGSTATPRTALL:
445 			flag |= DB_STAT_ALL;
446 			break;
447 		case LOGSTATPRTCLEAR:
448 			flag |= DB_STAT_CLEAR;
449 			break;
450 		}
451 		if (result != TCL_OK)
452 			break;
453 	}
454 	if (result != TCL_OK)
455 		goto error;
456 
457 	_debug_check();
458 	ret = dbenv->log_stat_print(dbenv, flag);
459 	result = _ReturnSetup(interp,
460 	    ret, DB_RETOK_STD(ret), "dbenv log_stat_print");
461 error:
462 	return (result);
463 
464 }
465 
466 /*
467  * logc_Cmd --
468  *	Implements the log cursor command.
469  *
470  * PUBLIC: int logc_Cmd __P((ClientData, Tcl_Interp *, int, Tcl_Obj * CONST*));
471  */
472 int
logc_Cmd(clientData,interp,objc,objv)473 logc_Cmd(clientData, interp, objc, objv)
474 	ClientData clientData;		/* Cursor handle */
475 	Tcl_Interp *interp;		/* Interpreter */
476 	int objc;			/* How many arguments? */
477 	Tcl_Obj *CONST objv[];		/* The argument objects */
478 {
479 	static const char *logccmds[] = {
480 		"close",
481 		"get",
482 		"version",
483 		NULL
484 	};
485 	enum logccmds {
486 		LOGCCLOSE,
487 		LOGCGET,
488 		LOGCVERSION
489 	};
490 	DB_LOGC *logc;
491 	DBTCL_INFO *logcip;
492 	Tcl_Obj *res;
493 	u_int32_t version;
494 	int cmdindex, result, ret;
495 
496 	Tcl_ResetResult(interp);
497 	logc = (DB_LOGC *)clientData;
498 	logcip = _PtrToInfo((void *)logc);
499 	result = TCL_OK;
500 
501 	if (objc <= 1) {
502 		Tcl_WrongNumArgs(interp, 1, objv, "command cmdargs");
503 		return (TCL_ERROR);
504 	}
505 	if (logc == NULL) {
506 		Tcl_SetResult(interp, "NULL logc pointer", TCL_STATIC);
507 		return (TCL_ERROR);
508 	}
509 	if (logcip == NULL) {
510 		Tcl_SetResult(interp, "NULL logc info pointer", TCL_STATIC);
511 		return (TCL_ERROR);
512 	}
513 
514 	/*
515 	 * Get the command name index from the object based on the berkdbcmds
516 	 * defined above.
517 	 */
518 	if (Tcl_GetIndexFromObj(interp, objv[1], logccmds, "command",
519 	    TCL_EXACT, &cmdindex) != TCL_OK)
520 		return (IS_HELP(objv[1]));
521 	switch ((enum logccmds)cmdindex) {
522 	case LOGCCLOSE:
523 		/*
524 		 * No args for this.  Error if there are some.
525 		 */
526 		if (objc > 2) {
527 			Tcl_WrongNumArgs(interp, 2, objv, NULL);
528 			return (TCL_ERROR);
529 		}
530 		_debug_check();
531 		ret = logc->close(logc, 0);
532 		result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
533 		    "logc close");
534 		if (result == TCL_OK) {
535 			(void)Tcl_DeleteCommand(interp, logcip->i_name);
536 			_DeleteInfo(logcip);
537 		}
538 		break;
539 	case LOGCGET:
540 		result = tcl_LogcGet(interp, objc, objv, logc);
541 		break;
542 	case LOGCVERSION:
543 		/*
544 		 * No args for this.  Error if there are some.
545 		 */
546 		if (objc > 2) {
547 			Tcl_WrongNumArgs(interp, 2, objv, NULL);
548 			return (TCL_ERROR);
549 		}
550 		_debug_check();
551 		ret = logc->version(logc, &version, 0);
552 		if ((result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
553 		    "logc version")) == TCL_OK) {
554 			res = Tcl_NewIntObj((int)version);
555 			Tcl_SetObjResult(interp, res);
556 		}
557 		break;
558 	}
559 
560 	return (result);
561 }
562 
563 static int
tcl_LogcGet(interp,objc,objv,logc)564 tcl_LogcGet(interp, objc, objv, logc)
565 	Tcl_Interp *interp;
566 	int objc;
567 	Tcl_Obj * CONST *objv;
568 	DB_LOGC *logc;
569 {
570 	static const char *logcgetopts[] = {
571 		"-current",
572 		"-first",
573 		"-last",
574 		"-next",
575 		"-prev",
576 		"-set",
577 		NULL
578 	};
579 	enum logcgetopts {
580 		LOGCGET_CURRENT,
581 		LOGCGET_FIRST,
582 		LOGCGET_LAST,
583 		LOGCGET_NEXT,
584 		LOGCGET_PREV,
585 		LOGCGET_SET
586 	};
587 	DB_LSN lsn;
588 	DBT data;
589 	Tcl_Obj *dataobj, *lsnlist, *myobjv[2], *res;
590 	u_int32_t flag;
591 	int i, myobjc, optindex, result, ret;
592 
593 	result = TCL_OK;
594 	res = NULL;
595 	flag = 0;
596 
597 	if (objc < 3) {
598 		Tcl_WrongNumArgs(interp, 2, objv, "?-args? lsn");
599 		return (TCL_ERROR);
600 	}
601 
602 	/*
603 	 * Get the command name index from the object based on the options
604 	 * defined above.
605 	 */
606 	i = 2;
607 	while (i < objc) {
608 		if (Tcl_GetIndexFromObj(interp, objv[i],
609 		    logcgetopts, "option", TCL_EXACT, &optindex) != TCL_OK)
610 			return (IS_HELP(objv[i]));
611 		i++;
612 		switch ((enum logcgetopts)optindex) {
613 		case LOGCGET_CURRENT:
614 			FLAG_CHECK(flag);
615 			flag |= DB_CURRENT;
616 			break;
617 		case LOGCGET_FIRST:
618 			FLAG_CHECK(flag);
619 			flag |= DB_FIRST;
620 			break;
621 		case LOGCGET_LAST:
622 			FLAG_CHECK(flag);
623 			flag |= DB_LAST;
624 			break;
625 		case LOGCGET_NEXT:
626 			FLAG_CHECK(flag);
627 			flag |= DB_NEXT;
628 			break;
629 		case LOGCGET_PREV:
630 			FLAG_CHECK(flag);
631 			flag |= DB_PREV;
632 			break;
633 		case LOGCGET_SET:
634 			FLAG_CHECK(flag);
635 			flag |= DB_SET;
636 			if (i == objc) {
637 				Tcl_WrongNumArgs(interp, 2, objv, "?-set lsn?");
638 				result = TCL_ERROR;
639 				break;
640 			}
641 			result = _GetLsn(interp, objv[i++], &lsn);
642 			break;
643 		}
644 	}
645 
646 	if (result == TCL_ERROR)
647 		return (result);
648 
649 	memset(&data, 0, sizeof(data));
650 
651 	_debug_check();
652 	ret = logc->get(logc, &lsn, &data, flag);
653 
654 	res = Tcl_NewListObj(0, NULL);
655 	if (res == NULL)
656 		goto memerr;
657 
658 	if (ret == 0) {
659 		/*
660 		 * Success.  Set up return list as {LSN data} where LSN
661 		 * is a sublist {file offset}.
662 		 */
663 		myobjc = 2;
664 		myobjv[0] = Tcl_NewWideIntObj((Tcl_WideInt)lsn.file);
665 		myobjv[1] = Tcl_NewWideIntObj((Tcl_WideInt)lsn.offset);
666 		lsnlist = Tcl_NewListObj(myobjc, myobjv);
667 		if (lsnlist == NULL)
668 			goto memerr;
669 
670 		result = Tcl_ListObjAppendElement(interp, res, lsnlist);
671 		dataobj = NewStringObj(data.data, data.size);
672 		if (dataobj == NULL) {
673 			goto memerr;
674 		}
675 		result = Tcl_ListObjAppendElement(interp, res, dataobj);
676 	} else
677 		result = _ReturnSetup(interp, ret, DB_RETOK_LGGET(ret),
678 		    "DB_LOGC->get");
679 
680 	Tcl_SetObjResult(interp, res);
681 
682 	if (0) {
683 memerr:		if (res != NULL) {
684 			Tcl_DecrRefCount(res);
685 		}
686 		Tcl_SetResult(interp, "allocation failed", TCL_STATIC);
687 	}
688 
689 	return (result);
690 }
691 
692 static const char *confwhich[] = {
693 	"autoremove",
694 	"direct",
695 	"dsync",
696 	"inmemory",
697 	"zero",
698 	NULL
699 };
700 enum logwhich {
701 	LOGCONF_AUTO,
702 	LOGCONF_DIRECT,
703 	LOGCONF_DSYNC,
704 	LOGCONF_INMEMORY,
705 	LOGCONF_ZERO
706 };
707 
708 /*
709  * tcl_LogConfig --
710  *	Call DB_ENV->log_set_config().
711  *
712  * PUBLIC: int tcl_LogConfig
713  * PUBLIC:     __P((Tcl_Interp *, DB_ENV *, Tcl_Obj *, Tcl_Obj *));
714  */
715 int
tcl_LogConfig(interp,dbenv,which,onoff)716 tcl_LogConfig(interp, dbenv, which, onoff)
717 	Tcl_Interp *interp;		/* Interpreter */
718 	DB_ENV *dbenv;			/* Environment pointer */
719 	Tcl_Obj *which;			/* {which on|off} */
720 	Tcl_Obj *onoff;
721 {
722 	static const char *confonoff[] = {
723 		"off",
724 		"on",
725 		NULL
726 	};
727 	enum confonoff {
728 		LOGCONF_OFF,
729 		LOGCONF_ON
730 	};
731 	int on, optindex, ret;
732 	u_int32_t wh;
733 
734 	if (Tcl_GetIndexFromObj(interp,
735 	    which, confwhich, "option", TCL_EXACT, &optindex) != TCL_OK)
736 		return (IS_HELP(which));
737 
738 	switch ((enum logwhich)optindex) {
739 	case LOGCONF_AUTO:
740 		wh = DB_LOG_AUTO_REMOVE;
741 		break;
742 	case LOGCONF_DIRECT:
743 		wh = DB_LOG_DIRECT;
744 		break;
745 	case LOGCONF_DSYNC:
746 		wh = DB_LOG_DSYNC;
747 		break;
748 	case LOGCONF_INMEMORY:
749 		wh = DB_LOG_IN_MEMORY;
750 		break;
751 	case LOGCONF_ZERO:
752 		wh = DB_LOG_ZERO;
753 		break;
754 	default:
755 		return (TCL_ERROR);
756 	}
757 	if (Tcl_GetIndexFromObj(interp,
758 	    onoff, confonoff, "option", TCL_EXACT, &optindex) != TCL_OK)
759 		return (IS_HELP(onoff));
760 	switch ((enum confonoff)optindex) {
761 	case LOGCONF_OFF:
762 		on = 0;
763 		break;
764 	case LOGCONF_ON:
765 		on = 1;
766 		break;
767 	default:
768 		return (TCL_ERROR);
769 	}
770 	ret = dbenv->log_set_config(dbenv, wh, on);
771 	return (_ReturnSetup(interp, ret, DB_RETOK_STD(ret),
772 	    "env rep_config"));
773 }
774 
775 /*
776  * tcl_LogGetConfig --
777  *	Call DB_ENV->rep_get_config().
778  *
779  * PUBLIC: int tcl_LogGetConfig
780  * PUBLIC:     __P((Tcl_Interp *, DB_ENV *, Tcl_Obj *));
781  */
782 int
tcl_LogGetConfig(interp,dbenv,which)783 tcl_LogGetConfig(interp, dbenv, which)
784 	Tcl_Interp *interp;		/* Interpreter */
785 	DB_ENV *dbenv;			/* Environment pointer */
786 	Tcl_Obj *which;			/* which flag */
787 {
788 	Tcl_Obj *res;
789 	int on, optindex, result, ret;
790 	u_int32_t wh;
791 
792 	if (Tcl_GetIndexFromObj(interp, which, confwhich, "option",
793 	    TCL_EXACT, &optindex) != TCL_OK)
794 		return (IS_HELP(which));
795 
796 	res = NULL;
797 	switch ((enum logwhich)optindex) {
798 	case LOGCONF_AUTO:
799 		wh = DB_LOG_AUTO_REMOVE;
800 		break;
801 	case LOGCONF_DIRECT:
802 		wh = DB_LOG_DIRECT;
803 		break;
804 	case LOGCONF_DSYNC:
805 		wh = DB_LOG_DSYNC;
806 		break;
807 	case LOGCONF_INMEMORY:
808 		wh = DB_LOG_IN_MEMORY;
809 		break;
810 	case LOGCONF_ZERO:
811 		wh = DB_LOG_ZERO;
812 		break;
813 	default:
814 		return (TCL_ERROR);
815 	}
816 	ret = dbenv->log_get_config(dbenv, wh, &on);
817 	if ((result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
818 	    "env log_config")) == TCL_OK) {
819 		res = Tcl_NewIntObj(on);
820 		Tcl_SetObjResult(interp, res);
821 	}
822 	return (result);
823 }
824 #endif
825