xref: /illumos-gate/usr/src/cmd/sendmail/db/log/log_get.c (revision 7c478bd9)
1*7c478bd9Sstevel@tonic-gate /*-
2*7c478bd9Sstevel@tonic-gate  * See the file LICENSE for redistribution information.
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * Copyright (c) 1996, 1997, 1998
5*7c478bd9Sstevel@tonic-gate  *	Sleepycat Software.  All rights reserved.
6*7c478bd9Sstevel@tonic-gate  */
7*7c478bd9Sstevel@tonic-gate #include "config.h"
8*7c478bd9Sstevel@tonic-gate 
9*7c478bd9Sstevel@tonic-gate #ifndef lint
10*7c478bd9Sstevel@tonic-gate static const char sccsid[] = "@(#)log_get.c	10.38 (Sleepycat) 10/3/98";
11*7c478bd9Sstevel@tonic-gate #endif /* not lint */
12*7c478bd9Sstevel@tonic-gate 
13*7c478bd9Sstevel@tonic-gate #ifndef NO_SYSTEM_INCLUDES
14*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
15*7c478bd9Sstevel@tonic-gate 
16*7c478bd9Sstevel@tonic-gate #include <errno.h>
17*7c478bd9Sstevel@tonic-gate #include <string.h>
18*7c478bd9Sstevel@tonic-gate #include <unistd.h>
19*7c478bd9Sstevel@tonic-gate #endif
20*7c478bd9Sstevel@tonic-gate 
21*7c478bd9Sstevel@tonic-gate #include "db_int.h"
22*7c478bd9Sstevel@tonic-gate #include "shqueue.h"
23*7c478bd9Sstevel@tonic-gate #include "db_page.h"
24*7c478bd9Sstevel@tonic-gate #include "log.h"
25*7c478bd9Sstevel@tonic-gate #include "hash.h"
26*7c478bd9Sstevel@tonic-gate #include "common_ext.h"
27*7c478bd9Sstevel@tonic-gate 
28*7c478bd9Sstevel@tonic-gate /*
29*7c478bd9Sstevel@tonic-gate  * log_get --
30*7c478bd9Sstevel@tonic-gate  *	Get a log record.
31*7c478bd9Sstevel@tonic-gate  */
32*7c478bd9Sstevel@tonic-gate int
log_get(dblp,alsn,dbt,flags)33*7c478bd9Sstevel@tonic-gate log_get(dblp, alsn, dbt, flags)
34*7c478bd9Sstevel@tonic-gate 	DB_LOG *dblp;
35*7c478bd9Sstevel@tonic-gate 	DB_LSN *alsn;
36*7c478bd9Sstevel@tonic-gate 	DBT *dbt;
37*7c478bd9Sstevel@tonic-gate 	u_int32_t flags;
38*7c478bd9Sstevel@tonic-gate {
39*7c478bd9Sstevel@tonic-gate 	int ret;
40*7c478bd9Sstevel@tonic-gate 
41*7c478bd9Sstevel@tonic-gate 	LOG_PANIC_CHECK(dblp);
42*7c478bd9Sstevel@tonic-gate 
43*7c478bd9Sstevel@tonic-gate 	/* Validate arguments. */
44*7c478bd9Sstevel@tonic-gate 	if (flags != DB_CHECKPOINT && flags != DB_CURRENT &&
45*7c478bd9Sstevel@tonic-gate 	    flags != DB_FIRST && flags != DB_LAST &&
46*7c478bd9Sstevel@tonic-gate 	    flags != DB_NEXT && flags != DB_PREV && flags != DB_SET)
47*7c478bd9Sstevel@tonic-gate 		return (__db_ferr(dblp->dbenv, "log_get", 1));
48*7c478bd9Sstevel@tonic-gate 
49*7c478bd9Sstevel@tonic-gate 	if (F_ISSET(dblp, DB_AM_THREAD)) {
50*7c478bd9Sstevel@tonic-gate 		if (flags == DB_NEXT || flags == DB_PREV || flags == DB_CURRENT)
51*7c478bd9Sstevel@tonic-gate 			return (__db_ferr(dblp->dbenv, "log_get", 1));
52*7c478bd9Sstevel@tonic-gate 		if (!F_ISSET(dbt, DB_DBT_USERMEM | DB_DBT_MALLOC))
53*7c478bd9Sstevel@tonic-gate 			return (__db_ferr(dblp->dbenv, "threaded data", 1));
54*7c478bd9Sstevel@tonic-gate 	}
55*7c478bd9Sstevel@tonic-gate 
56*7c478bd9Sstevel@tonic-gate 	LOCK_LOGREGION(dblp);
57*7c478bd9Sstevel@tonic-gate 
58*7c478bd9Sstevel@tonic-gate 	/*
59*7c478bd9Sstevel@tonic-gate 	 * If we get one of the log's header records, repeat the operation.
60*7c478bd9Sstevel@tonic-gate 	 * This assumes that applications don't ever request the log header
61*7c478bd9Sstevel@tonic-gate 	 * records by LSN, but that seems reasonable to me.
62*7c478bd9Sstevel@tonic-gate 	 */
63*7c478bd9Sstevel@tonic-gate 	ret = __log_get(dblp, alsn, dbt, flags, 0);
64*7c478bd9Sstevel@tonic-gate 	if (ret == 0 && alsn->offset == 0) {
65*7c478bd9Sstevel@tonic-gate 		switch (flags) {
66*7c478bd9Sstevel@tonic-gate 		case DB_FIRST:
67*7c478bd9Sstevel@tonic-gate 			flags = DB_NEXT;
68*7c478bd9Sstevel@tonic-gate 			break;
69*7c478bd9Sstevel@tonic-gate 		case DB_LAST:
70*7c478bd9Sstevel@tonic-gate 			flags = DB_PREV;
71*7c478bd9Sstevel@tonic-gate 			break;
72*7c478bd9Sstevel@tonic-gate 		}
73*7c478bd9Sstevel@tonic-gate 		ret = __log_get(dblp, alsn, dbt, flags, 0);
74*7c478bd9Sstevel@tonic-gate 	}
75*7c478bd9Sstevel@tonic-gate 
76*7c478bd9Sstevel@tonic-gate 	UNLOCK_LOGREGION(dblp);
77*7c478bd9Sstevel@tonic-gate 
78*7c478bd9Sstevel@tonic-gate 	return (ret);
79*7c478bd9Sstevel@tonic-gate }
80*7c478bd9Sstevel@tonic-gate 
81*7c478bd9Sstevel@tonic-gate /*
82*7c478bd9Sstevel@tonic-gate  * __log_get --
83*7c478bd9Sstevel@tonic-gate  *	Get a log record; internal version.
84*7c478bd9Sstevel@tonic-gate  *
85*7c478bd9Sstevel@tonic-gate  * PUBLIC: int __log_get __P((DB_LOG *, DB_LSN *, DBT *, u_int32_t, int));
86*7c478bd9Sstevel@tonic-gate  */
87*7c478bd9Sstevel@tonic-gate int
__log_get(dblp,alsn,dbt,flags,silent)88*7c478bd9Sstevel@tonic-gate __log_get(dblp, alsn, dbt, flags, silent)
89*7c478bd9Sstevel@tonic-gate 	DB_LOG *dblp;
90*7c478bd9Sstevel@tonic-gate 	DB_LSN *alsn;
91*7c478bd9Sstevel@tonic-gate 	DBT *dbt;
92*7c478bd9Sstevel@tonic-gate 	u_int32_t flags;
93*7c478bd9Sstevel@tonic-gate 	int silent;
94*7c478bd9Sstevel@tonic-gate {
95*7c478bd9Sstevel@tonic-gate 	DB_LSN nlsn;
96*7c478bd9Sstevel@tonic-gate 	HDR hdr;
97*7c478bd9Sstevel@tonic-gate 	LOG *lp;
98*7c478bd9Sstevel@tonic-gate 	size_t len;
99*7c478bd9Sstevel@tonic-gate 	ssize_t nr;
100*7c478bd9Sstevel@tonic-gate 	int cnt, ret;
101*7c478bd9Sstevel@tonic-gate 	char *np, *tbuf;
102*7c478bd9Sstevel@tonic-gate 	const char *fail;
103*7c478bd9Sstevel@tonic-gate 	void *p, *shortp;
104*7c478bd9Sstevel@tonic-gate 
105*7c478bd9Sstevel@tonic-gate 	lp = dblp->lp;
106*7c478bd9Sstevel@tonic-gate 	fail = np = tbuf = NULL;
107*7c478bd9Sstevel@tonic-gate 
108*7c478bd9Sstevel@tonic-gate 	nlsn = dblp->c_lsn;
109*7c478bd9Sstevel@tonic-gate 	switch (flags) {
110*7c478bd9Sstevel@tonic-gate 	case DB_CHECKPOINT:
111*7c478bd9Sstevel@tonic-gate 		nlsn = lp->chkpt_lsn;
112*7c478bd9Sstevel@tonic-gate 		if (IS_ZERO_LSN(nlsn)) {
113*7c478bd9Sstevel@tonic-gate 			__db_err(dblp->dbenv,
114*7c478bd9Sstevel@tonic-gate 	"log_get: unable to find checkpoint record: no checkpoint set.");
115*7c478bd9Sstevel@tonic-gate 			ret = ENOENT;
116*7c478bd9Sstevel@tonic-gate 			goto err2;
117*7c478bd9Sstevel@tonic-gate 		}
118*7c478bd9Sstevel@tonic-gate 		break;
119*7c478bd9Sstevel@tonic-gate 	case DB_NEXT:				/* Next log record. */
120*7c478bd9Sstevel@tonic-gate 		if (!IS_ZERO_LSN(nlsn)) {
121*7c478bd9Sstevel@tonic-gate 			/* Increment the cursor by the cursor record size. */
122*7c478bd9Sstevel@tonic-gate 			nlsn.offset += dblp->c_len;
123*7c478bd9Sstevel@tonic-gate 			break;
124*7c478bd9Sstevel@tonic-gate 		}
125*7c478bd9Sstevel@tonic-gate 		/* FALLTHROUGH */
126*7c478bd9Sstevel@tonic-gate 	case DB_FIRST:				/* Find the first log record. */
127*7c478bd9Sstevel@tonic-gate 		/* Find the first log file. */
128*7c478bd9Sstevel@tonic-gate 		if ((ret = __log_find(dblp, 1, &cnt)) != 0)
129*7c478bd9Sstevel@tonic-gate 			goto err2;
130*7c478bd9Sstevel@tonic-gate 
131*7c478bd9Sstevel@tonic-gate 		/*
132*7c478bd9Sstevel@tonic-gate 		 * We may have only entered records in the buffer, and not
133*7c478bd9Sstevel@tonic-gate 		 * yet written a log file.  If no log files were found and
134*7c478bd9Sstevel@tonic-gate 		 * there's anything in the buffer, it belongs to file 1.
135*7c478bd9Sstevel@tonic-gate 		 */
136*7c478bd9Sstevel@tonic-gate 		if (cnt == 0)
137*7c478bd9Sstevel@tonic-gate 			cnt = 1;
138*7c478bd9Sstevel@tonic-gate 
139*7c478bd9Sstevel@tonic-gate 		nlsn.file = cnt;
140*7c478bd9Sstevel@tonic-gate 		nlsn.offset = 0;
141*7c478bd9Sstevel@tonic-gate 		break;
142*7c478bd9Sstevel@tonic-gate 	case DB_CURRENT:			/* Current log record. */
143*7c478bd9Sstevel@tonic-gate 		break;
144*7c478bd9Sstevel@tonic-gate 	case DB_PREV:				/* Previous log record. */
145*7c478bd9Sstevel@tonic-gate 		if (!IS_ZERO_LSN(nlsn)) {
146*7c478bd9Sstevel@tonic-gate 			/* If at start-of-file, move to the previous file. */
147*7c478bd9Sstevel@tonic-gate 			if (nlsn.offset == 0) {
148*7c478bd9Sstevel@tonic-gate 				if (nlsn.file == 1 ||
149*7c478bd9Sstevel@tonic-gate 				    __log_valid(dblp, nlsn.file - 1, 0) != 0)
150*7c478bd9Sstevel@tonic-gate 					return (DB_NOTFOUND);
151*7c478bd9Sstevel@tonic-gate 
152*7c478bd9Sstevel@tonic-gate 				--nlsn.file;
153*7c478bd9Sstevel@tonic-gate 				nlsn.offset = dblp->c_off;
154*7c478bd9Sstevel@tonic-gate 			} else
155*7c478bd9Sstevel@tonic-gate 				nlsn.offset = dblp->c_off;
156*7c478bd9Sstevel@tonic-gate 			break;
157*7c478bd9Sstevel@tonic-gate 		}
158*7c478bd9Sstevel@tonic-gate 		/* FALLTHROUGH */
159*7c478bd9Sstevel@tonic-gate 	case DB_LAST:				/* Last log record. */
160*7c478bd9Sstevel@tonic-gate 		nlsn.file = lp->lsn.file;
161*7c478bd9Sstevel@tonic-gate 		nlsn.offset = lp->lsn.offset - lp->len;
162*7c478bd9Sstevel@tonic-gate 		break;
163*7c478bd9Sstevel@tonic-gate 	case DB_SET:				/* Set log record. */
164*7c478bd9Sstevel@tonic-gate 		nlsn = *alsn;
165*7c478bd9Sstevel@tonic-gate 		break;
166*7c478bd9Sstevel@tonic-gate 	}
167*7c478bd9Sstevel@tonic-gate 
168*7c478bd9Sstevel@tonic-gate retry:
169*7c478bd9Sstevel@tonic-gate 	/* Return 1 if the request is past end-of-file. */
170*7c478bd9Sstevel@tonic-gate 	if (nlsn.file > lp->lsn.file ||
171*7c478bd9Sstevel@tonic-gate 	    (nlsn.file == lp->lsn.file && nlsn.offset >= lp->lsn.offset))
172*7c478bd9Sstevel@tonic-gate 		return (DB_NOTFOUND);
173*7c478bd9Sstevel@tonic-gate 
174*7c478bd9Sstevel@tonic-gate 	/* If we've switched files, discard the current fd. */
175*7c478bd9Sstevel@tonic-gate 	if (dblp->c_lsn.file != nlsn.file && dblp->c_fd != -1) {
176*7c478bd9Sstevel@tonic-gate 		(void)__os_close(dblp->c_fd);
177*7c478bd9Sstevel@tonic-gate 		dblp->c_fd = -1;
178*7c478bd9Sstevel@tonic-gate 	}
179*7c478bd9Sstevel@tonic-gate 
180*7c478bd9Sstevel@tonic-gate 	/* If the entire record is in the in-memory buffer, copy it out. */
181*7c478bd9Sstevel@tonic-gate 	if (nlsn.file == lp->lsn.file && nlsn.offset >= lp->w_off) {
182*7c478bd9Sstevel@tonic-gate 		/* Copy the header. */
183*7c478bd9Sstevel@tonic-gate 		p = lp->buf + (nlsn.offset - lp->w_off);
184*7c478bd9Sstevel@tonic-gate 		memcpy(&hdr, p, sizeof(HDR));
185*7c478bd9Sstevel@tonic-gate 
186*7c478bd9Sstevel@tonic-gate 		/* Copy the record. */
187*7c478bd9Sstevel@tonic-gate 		len = hdr.len - sizeof(HDR);
188*7c478bd9Sstevel@tonic-gate 		if ((ret = __db_retcopy(dbt, (u_int8_t *)p + sizeof(HDR),
189*7c478bd9Sstevel@tonic-gate 		    len, &dblp->c_dbt.data, &dblp->c_dbt.ulen, NULL)) != 0)
190*7c478bd9Sstevel@tonic-gate 			goto err1;
191*7c478bd9Sstevel@tonic-gate 		goto cksum;
192*7c478bd9Sstevel@tonic-gate 	}
193*7c478bd9Sstevel@tonic-gate 
194*7c478bd9Sstevel@tonic-gate 	/* Acquire a file descriptor. */
195*7c478bd9Sstevel@tonic-gate 	if (dblp->c_fd == -1) {
196*7c478bd9Sstevel@tonic-gate 		if ((ret = __log_name(dblp, nlsn.file,
197*7c478bd9Sstevel@tonic-gate 		    &np, &dblp->c_fd, DB_RDONLY | DB_SEQUENTIAL)) != 0) {
198*7c478bd9Sstevel@tonic-gate 			fail = np;
199*7c478bd9Sstevel@tonic-gate 			goto err1;
200*7c478bd9Sstevel@tonic-gate 		}
201*7c478bd9Sstevel@tonic-gate 		__os_freestr(np);
202*7c478bd9Sstevel@tonic-gate 		np = NULL;
203*7c478bd9Sstevel@tonic-gate 	}
204*7c478bd9Sstevel@tonic-gate 
205*7c478bd9Sstevel@tonic-gate 	/* Seek to the header offset and read the header. */
206*7c478bd9Sstevel@tonic-gate 	if ((ret =
207*7c478bd9Sstevel@tonic-gate 	    __os_seek(dblp->c_fd, 0, 0, nlsn.offset, 0, SEEK_SET)) != 0) {
208*7c478bd9Sstevel@tonic-gate 		fail = "seek";
209*7c478bd9Sstevel@tonic-gate 		goto err1;
210*7c478bd9Sstevel@tonic-gate 	}
211*7c478bd9Sstevel@tonic-gate 	if ((ret = __os_read(dblp->c_fd, &hdr, sizeof(HDR), &nr)) != 0) {
212*7c478bd9Sstevel@tonic-gate 		fail = "read";
213*7c478bd9Sstevel@tonic-gate 		goto err1;
214*7c478bd9Sstevel@tonic-gate 	}
215*7c478bd9Sstevel@tonic-gate 	if (nr == sizeof(HDR))
216*7c478bd9Sstevel@tonic-gate 		shortp = NULL;
217*7c478bd9Sstevel@tonic-gate 	else {
218*7c478bd9Sstevel@tonic-gate 		/* If read returns EOF, try the next file. */
219*7c478bd9Sstevel@tonic-gate 		if (nr == 0) {
220*7c478bd9Sstevel@tonic-gate 			if (flags != DB_NEXT || nlsn.file == lp->lsn.file)
221*7c478bd9Sstevel@tonic-gate 				goto corrupt;
222*7c478bd9Sstevel@tonic-gate 
223*7c478bd9Sstevel@tonic-gate 			/* Move to the next file. */
224*7c478bd9Sstevel@tonic-gate 			++nlsn.file;
225*7c478bd9Sstevel@tonic-gate 			nlsn.offset = 0;
226*7c478bd9Sstevel@tonic-gate 			goto retry;
227*7c478bd9Sstevel@tonic-gate 		}
228*7c478bd9Sstevel@tonic-gate 
229*7c478bd9Sstevel@tonic-gate 		/*
230*7c478bd9Sstevel@tonic-gate 		 * If read returns a short count the rest of the record has
231*7c478bd9Sstevel@tonic-gate 		 * to be in the in-memory buffer.
232*7c478bd9Sstevel@tonic-gate 		 */
233*7c478bd9Sstevel@tonic-gate 		if (lp->b_off < sizeof(HDR) - nr)
234*7c478bd9Sstevel@tonic-gate 			goto corrupt;
235*7c478bd9Sstevel@tonic-gate 
236*7c478bd9Sstevel@tonic-gate 		/* Get the rest of the header from the in-memory buffer. */
237*7c478bd9Sstevel@tonic-gate 		memcpy((u_int8_t *)&hdr + nr, lp->buf, sizeof(HDR) - nr);
238*7c478bd9Sstevel@tonic-gate 		shortp = lp->buf + (sizeof(HDR) - nr);
239*7c478bd9Sstevel@tonic-gate 	}
240*7c478bd9Sstevel@tonic-gate 
241*7c478bd9Sstevel@tonic-gate 	/*
242*7c478bd9Sstevel@tonic-gate 	 * Check for buffers of 0's, that's what we usually see during
243*7c478bd9Sstevel@tonic-gate 	 * recovery, although it's certainly not something on which we
244*7c478bd9Sstevel@tonic-gate 	 * can depend.
245*7c478bd9Sstevel@tonic-gate 	 */
246*7c478bd9Sstevel@tonic-gate 	if (hdr.len <= sizeof(HDR))
247*7c478bd9Sstevel@tonic-gate 		goto corrupt;
248*7c478bd9Sstevel@tonic-gate 	len = hdr.len - sizeof(HDR);
249*7c478bd9Sstevel@tonic-gate 
250*7c478bd9Sstevel@tonic-gate 	/* If we've already moved to the in-memory buffer, fill from there. */
251*7c478bd9Sstevel@tonic-gate 	if (shortp != NULL) {
252*7c478bd9Sstevel@tonic-gate 		if (lp->b_off < ((u_int8_t *)shortp - lp->buf) + len)
253*7c478bd9Sstevel@tonic-gate 			goto corrupt;
254*7c478bd9Sstevel@tonic-gate 		if ((ret = __db_retcopy(dbt, shortp, len,
255*7c478bd9Sstevel@tonic-gate 		    &dblp->c_dbt.data, &dblp->c_dbt.ulen, NULL)) != 0)
256*7c478bd9Sstevel@tonic-gate 			goto err1;
257*7c478bd9Sstevel@tonic-gate 		goto cksum;
258*7c478bd9Sstevel@tonic-gate 	}
259*7c478bd9Sstevel@tonic-gate 
260*7c478bd9Sstevel@tonic-gate 	/*
261*7c478bd9Sstevel@tonic-gate 	 * Allocate temporary memory to hold the record.
262*7c478bd9Sstevel@tonic-gate 	 *
263*7c478bd9Sstevel@tonic-gate 	 * XXX
264*7c478bd9Sstevel@tonic-gate 	 * We're calling malloc(3) with a region locked.  This isn't
265*7c478bd9Sstevel@tonic-gate 	 * a good idea.
266*7c478bd9Sstevel@tonic-gate 	 */
267*7c478bd9Sstevel@tonic-gate 	if ((ret = __os_malloc(len, NULL, &tbuf)) != 0)
268*7c478bd9Sstevel@tonic-gate 		goto err1;
269*7c478bd9Sstevel@tonic-gate 
270*7c478bd9Sstevel@tonic-gate 	/*
271*7c478bd9Sstevel@tonic-gate 	 * Read the record into the buffer.  If read returns a short count,
272*7c478bd9Sstevel@tonic-gate 	 * there was an error or the rest of the record is in the in-memory
273*7c478bd9Sstevel@tonic-gate 	 * buffer.  Note, the information may be garbage if we're in recovery,
274*7c478bd9Sstevel@tonic-gate 	 * so don't read past the end of the buffer's memory.
275*7c478bd9Sstevel@tonic-gate 	 */
276*7c478bd9Sstevel@tonic-gate 	if ((ret = __os_read(dblp->c_fd, tbuf, len, &nr)) != 0) {
277*7c478bd9Sstevel@tonic-gate 		fail = "read";
278*7c478bd9Sstevel@tonic-gate 		goto err1;
279*7c478bd9Sstevel@tonic-gate 	}
280*7c478bd9Sstevel@tonic-gate 	if (len - nr > sizeof(lp->buf))
281*7c478bd9Sstevel@tonic-gate 		goto corrupt;
282*7c478bd9Sstevel@tonic-gate 	if (nr != (ssize_t)len) {
283*7c478bd9Sstevel@tonic-gate 		if (lp->b_off < len - nr)
284*7c478bd9Sstevel@tonic-gate 			goto corrupt;
285*7c478bd9Sstevel@tonic-gate 
286*7c478bd9Sstevel@tonic-gate 		/* Get the rest of the record from the in-memory buffer. */
287*7c478bd9Sstevel@tonic-gate 		memcpy((u_int8_t *)tbuf + nr, lp->buf, len - nr);
288*7c478bd9Sstevel@tonic-gate 	}
289*7c478bd9Sstevel@tonic-gate 
290*7c478bd9Sstevel@tonic-gate 	/* Copy the record into the user's DBT. */
291*7c478bd9Sstevel@tonic-gate 	if ((ret = __db_retcopy(dbt, tbuf, len,
292*7c478bd9Sstevel@tonic-gate 	    &dblp->c_dbt.data, &dblp->c_dbt.ulen, NULL)) != 0)
293*7c478bd9Sstevel@tonic-gate 		goto err1;
294*7c478bd9Sstevel@tonic-gate 	__os_free(tbuf, 0);
295*7c478bd9Sstevel@tonic-gate 	tbuf = NULL;
296*7c478bd9Sstevel@tonic-gate 
297*7c478bd9Sstevel@tonic-gate cksum:	if (hdr.cksum != __ham_func4(dbt->data, dbt->size)) {
298*7c478bd9Sstevel@tonic-gate 		if (!silent)
299*7c478bd9Sstevel@tonic-gate 			__db_err(dblp->dbenv, "log_get: checksum mismatch");
300*7c478bd9Sstevel@tonic-gate 		goto corrupt;
301*7c478bd9Sstevel@tonic-gate 	}
302*7c478bd9Sstevel@tonic-gate 
303*7c478bd9Sstevel@tonic-gate 	/* Update the cursor and the return lsn. */
304*7c478bd9Sstevel@tonic-gate 	dblp->c_off = hdr.prev;
305*7c478bd9Sstevel@tonic-gate 	dblp->c_len = hdr.len;
306*7c478bd9Sstevel@tonic-gate 	dblp->c_lsn = *alsn = nlsn;
307*7c478bd9Sstevel@tonic-gate 
308*7c478bd9Sstevel@tonic-gate 	return (0);
309*7c478bd9Sstevel@tonic-gate 
310*7c478bd9Sstevel@tonic-gate corrupt:/*
311*7c478bd9Sstevel@tonic-gate 	 * This is the catchall -- for some reason we didn't find enough
312*7c478bd9Sstevel@tonic-gate 	 * information or it wasn't reasonable information, and it wasn't
313*7c478bd9Sstevel@tonic-gate 	 * because a system call failed.
314*7c478bd9Sstevel@tonic-gate 	 */
315*7c478bd9Sstevel@tonic-gate 	ret = EIO;
316*7c478bd9Sstevel@tonic-gate 	fail = "read";
317*7c478bd9Sstevel@tonic-gate 
318*7c478bd9Sstevel@tonic-gate err1:	if (!silent)
319*7c478bd9Sstevel@tonic-gate 		if (fail == NULL)
320*7c478bd9Sstevel@tonic-gate 			__db_err(dblp->dbenv, "log_get: %s", strerror(ret));
321*7c478bd9Sstevel@tonic-gate 		else
322*7c478bd9Sstevel@tonic-gate 			__db_err(dblp->dbenv,
323*7c478bd9Sstevel@tonic-gate 			    "log_get: %s: %s", fail, strerror(ret));
324*7c478bd9Sstevel@tonic-gate err2:	if (np != NULL)
325*7c478bd9Sstevel@tonic-gate 		__os_freestr(np);
326*7c478bd9Sstevel@tonic-gate 	if (tbuf != NULL)
327*7c478bd9Sstevel@tonic-gate 		__os_free(tbuf, 0);
328*7c478bd9Sstevel@tonic-gate 	return (ret);
329*7c478bd9Sstevel@tonic-gate }
330