fifolog_reader.c revision 306910
1210284Sjmallett/*-
2232812Sjmallett * Copyright (c) 2005-2008 Poul-Henning Kamp
3215990Sjmallett * All rights reserved.
4210284Sjmallett *
5210284Sjmallett * Redistribution and use in source and binary forms, with or without
6215990Sjmallett * modification, are permitted provided that the following conditions
7215990Sjmallett * are met:
8215990Sjmallett * 1. Redistributions of source code must retain the above copyright
9210284Sjmallett *    notice, this list of conditions and the following disclaimer.
10215990Sjmallett * 2. Redistributions in binary form must reproduce the above copyright
11215990Sjmallett *    notice, this list of conditions and the following disclaimer in the
12210284Sjmallett *    documentation and/or other materials provided with the distribution.
13215990Sjmallett *
14215990Sjmallett * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15215990Sjmallett * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16215990Sjmallett * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17210284Sjmallett * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18232812Sjmallett * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19215990Sjmallett * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20215990Sjmallett * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21215990Sjmallett * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22210284Sjmallett * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23215990Sjmallett * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24215990Sjmallett * SUCH DAMAGE.
25215990Sjmallett *
26215990Sjmallett * $FreeBSD: stable/10/usr.sbin/fifolog/lib/fifolog_reader.c 306910 2016-10-09 19:58:27Z pfg $
27210284Sjmallett */
28215990Sjmallett
29232812Sjmallett#include <stdio.h>
30215990Sjmallett#include <unistd.h>
31215990Sjmallett#include <assert.h>
32215990Sjmallett#include <err.h>
33215990Sjmallett#include <time.h>
34215990Sjmallett#include <string.h>
35215990Sjmallett#include <stdlib.h>
36215990Sjmallett#include <zlib.h>
37215990Sjmallett#include <sys/endian.h>
38215990Sjmallett
39210284Sjmallett#include "fifolog.h"
40210284Sjmallett#include "libfifolog.h"
41210284Sjmallett#include "libfifolog_int.h"
42210284Sjmallett#include "miniobj.h"
43210284Sjmallett
44210284Sjmallett/*--------------------------------------------------------------------*/
45210284Sjmallett
46232812Sjmallettstruct fifolog_reader {
47210284Sjmallett	unsigned		magic;
48210284Sjmallett#define FIFOLOG_READER_MAGIC	0x1036d139
49210284Sjmallett	struct fifolog_file	*ff;
50210284Sjmallett	unsigned		olen;
51210284Sjmallett	unsigned char		*obuf;
52210284Sjmallett	time_t			now;
53210284Sjmallett};
54210284Sjmallett
55210284Sjmallettstruct fifolog_reader *
56210284Sjmallettfifolog_reader_open(const char *fname)
57210284Sjmallett{
58210284Sjmallett	const char *retval;
59210284Sjmallett	struct fifolog_reader *fr;
60210284Sjmallett	int i;
61210284Sjmallett
62210284Sjmallett	fr = calloc(sizeof *fr, 1);
63210284Sjmallett	if (fr == NULL)
64210284Sjmallett		err(1, "Cannot malloc");
65210284Sjmallett
66210284Sjmallett	retval = fifolog_int_open(&fr->ff, fname, 0);
67210284Sjmallett	if (retval != NULL)
68210284Sjmallett		err(1, "%s", retval);
69210284Sjmallett
70210284Sjmallett	fr->obuf = calloc(16, fr->ff->recsize);
71210284Sjmallett	if (fr->obuf == NULL)
72210284Sjmallett		err(1, "Cannot malloc");
73210284Sjmallett	fr->olen = fr->ff->recsize * 16;
74210284Sjmallett
75210284Sjmallett	i = inflateInit(fr->ff->zs);
76210284Sjmallett	assert(i == Z_OK);
77210284Sjmallett
78210284Sjmallett	fr->magic = FIFOLOG_READER_MAGIC;
79210284Sjmallett	return (fr);
80210284Sjmallett}
81210284Sjmallett
82210284Sjmallett/*
83210284Sjmallett * Find the next SYNC block
84210284Sjmallett *
85210284Sjmallett * Return:
86210284Sjmallett *	0 - empty fifolog
87210284Sjmallett *	1 - found sync block
88210284Sjmallett *	2 - would have wrapped around
89210284Sjmallett *	3 - End of written log.
90210284Sjmallett */
91210284Sjmallett
92210284Sjmallettstatic int
93210284Sjmallettfifolog_reader_findsync(const struct fifolog_file *ff, off_t *o)
94210284Sjmallett{
95210284Sjmallett	int e;
96210284Sjmallett	unsigned seq, seqs;
97210284Sjmallett
98210284Sjmallett	assert(*o < ff->logsize);
99210284Sjmallett	e = fifolog_int_read(ff, *o);
100210284Sjmallett	if (e)
101210284Sjmallett		err(1, "Read error (%d) while looking for SYNC", e);
102210284Sjmallett	seq = be32dec(ff->recbuf);
103210284Sjmallett	if (*o == 0 && seq == 0)
104210284Sjmallett		return (0);
105210284Sjmallett
106210284Sjmallett	if (ff->recbuf[4] & FIFOLOG_FLG_SYNC)
107210284Sjmallett		return (1);		/* That was easy... */
108210284Sjmallett	while(1) {
109210284Sjmallett		assert(*o < ff->logsize);
110210284Sjmallett		(*o)++;
111210284Sjmallett		seq++;
112210284Sjmallett		if (*o == ff->logsize)
113210284Sjmallett			return (2);	/* wraparound */
114210284Sjmallett		e = fifolog_int_read(ff, *o);
115210284Sjmallett		if (e)
116210284Sjmallett			err(1, "Read error (%d) while looking for SYNC", e);
117210284Sjmallett		seqs = be32dec(ff->recbuf);
118210284Sjmallett		if (seqs != seq)
119210284Sjmallett			return (3);		/* End of log */
120210284Sjmallett		if (ff->recbuf[4] & FIFOLOG_FLG_SYNC)
121210284Sjmallett			return (1);		/* Bingo! */
122210284Sjmallett	}
123210284Sjmallett}
124210284Sjmallett
125210284Sjmallett/*
126210284Sjmallett * Seek out a given timestamp
127210284Sjmallett */
128210284Sjmallett
129210284Sjmallettoff_t
130210284Sjmallettfifolog_reader_seek(const struct fifolog_reader *fr, time_t t0)
131210284Sjmallett{
132210284Sjmallett	off_t o, s, st;
133210284Sjmallett	time_t t, tt;
134210284Sjmallett	unsigned seq, seqs;
135210284Sjmallett	const char *retval;
136210284Sjmallett	int e;
137210284Sjmallett
138210284Sjmallett	CHECK_OBJ_NOTNULL(fr, FIFOLOG_READER_MAGIC);
139215990Sjmallett
140210284Sjmallett	/*
141210284Sjmallett	 * First, find the first SYNC block
142210284Sjmallett	 */
143210284Sjmallett	o = 0;
144210284Sjmallett	e = fifolog_reader_findsync(fr->ff, &o);
145210284Sjmallett	if (e == 0)
146210284Sjmallett		return (0);			/* empty fifolog */
147210284Sjmallett	assert(e == 1);
148210284Sjmallett
149210284Sjmallett	assert(fr->ff->recbuf[4] & FIFOLOG_FLG_SYNC);
150210284Sjmallett	seq = be32dec(fr->ff->recbuf);
151210284Sjmallett	t = be32dec(fr->ff->recbuf + 5);
152210284Sjmallett
153210284Sjmallett	if (t > t0) {
154210284Sjmallett		/* Check if there is a second older part we can use */
155210284Sjmallett		retval = fifolog_int_findend(fr->ff, &s);
156210284Sjmallett		if (retval != NULL)
157210284Sjmallett			err(1, "%s", retval);
158210284Sjmallett		s++;
159210284Sjmallett		e = fifolog_reader_findsync(fr->ff, &s);
160210284Sjmallett		if (e == 0)
161210284Sjmallett			return (0);		/* empty fifolog */
162210284Sjmallett		if (e == 1) {
163210284Sjmallett			o = s;
164210284Sjmallett			seq = be32dec(fr->ff->recbuf);
165210284Sjmallett			t = be32dec(fr->ff->recbuf + 5);
166210284Sjmallett		}
167210284Sjmallett	}
168210284Sjmallett
169210284Sjmallett	/* Now do a binary search to find the sync block right before t0 */
170210284Sjmallett	s = st = (fr->ff->logsize - o) / 2;
171210284Sjmallett	while (s > 1) {
172210284Sjmallett		/* We know we shouldn't wrap */
173210284Sjmallett		if (o + st > fr->ff->logsize + 1) {
174210284Sjmallett			s = st = s / 2;
175210284Sjmallett			continue;
176210284Sjmallett		}
177210284Sjmallett		e = fifolog_int_read(fr->ff, o + st);
178210284Sjmallett		if (e) {
179210284Sjmallett			s = st = s / 2;
180210284Sjmallett			continue;
181210284Sjmallett		}
182210284Sjmallett		/* If not in same part, sequence won't match */
183210284Sjmallett		seqs = be32dec(fr->ff->recbuf);
184210284Sjmallett		if (seqs != seq + st) {
185210284Sjmallett			s = st = s / 2;
186210284Sjmallett			continue;
187210284Sjmallett		}
188210284Sjmallett		/* If not sync block, try next */
189210284Sjmallett		if (!(fr->ff->recbuf[4] & FIFOLOG_FLG_SYNC)) {
190210284Sjmallett			st++;
191210284Sjmallett			continue;
192210284Sjmallett		}
193210284Sjmallett		/* Check timestamp */
194210284Sjmallett		tt = be32dec(fr->ff->recbuf + 5);
195210284Sjmallett		if (tt >= t0) {
196210284Sjmallett			s = st = s / 2;
197210284Sjmallett			continue;
198210284Sjmallett		}
199210284Sjmallett		o += st;
200210284Sjmallett		seq = seqs;
201210284Sjmallett	}
202210284Sjmallett	fprintf(stderr, "Read from %jx\n", o * fr->ff->recsize);
203210284Sjmallett	return (o);
204210284Sjmallett}
205210284Sjmallett
206210284Sjmallettstatic unsigned char *
207210284Sjmallettfifolog_reader_chop(struct fifolog_reader *fr, fifolog_reader_render_t *func, void *priv)
208210284Sjmallett{
209210284Sjmallett	u_char *p, *q;
210210284Sjmallett	uint32_t v, w, u;
211210284Sjmallett
212210284Sjmallett	p = fr->obuf;
213210284Sjmallett	q = fr->obuf + (fr->olen - fr->ff->zs->avail_out);
214210284Sjmallett
215210284Sjmallett	while (1) {
216210284Sjmallett		/* Make sure we have a complete header */
217210284Sjmallett		if (p + 5 >= q)
218210284Sjmallett			return (p);
219210284Sjmallett		w = 4;
220210284Sjmallett		u = be32dec(p);
221210284Sjmallett		if (u & FIFOLOG_TIMESTAMP) {
222210284Sjmallett			fr->now = be32dec(p + 4);
223210284Sjmallett			w += 4;
224210284Sjmallett		}
225210284Sjmallett		if (u & FIFOLOG_LENGTH) {
226210284Sjmallett			v = p[w];
227210284Sjmallett			w++;
228210284Sjmallett			if (p + w + v >= q)
229210284Sjmallett				return (p);
230210284Sjmallett		} else {
231210284Sjmallett			for (v = 0; p + v + w < q && p[v + w] != '\0'; v++)
232210284Sjmallett				continue;
233210284Sjmallett			if (p + v + w >= q)
234210284Sjmallett				return (p);
235210284Sjmallett			v++;
236210284Sjmallett		}
237210284Sjmallett		func(priv, fr->now, u, p + w, v);
238210284Sjmallett		p += w + v;
239210284Sjmallett	}
240210284Sjmallett}
241210284Sjmallett
242210284Sjmallett/*
243210284Sjmallett * Process fifolog until end of written log or provided timestamp
244210284Sjmallett */
245210284Sjmallett
246210284Sjmallettvoid
247210284Sjmallettfifolog_reader_process(struct fifolog_reader *fr, off_t from, fifolog_reader_render_t *func, void *priv, time_t end)
248210284Sjmallett{
249210284Sjmallett	uint32_t seq, lseq;
250210284Sjmallett	off_t o = from;
251210284Sjmallett	int i, e;
252210284Sjmallett	time_t t;
253210284Sjmallett	u_char *p, *q;
254210284Sjmallett	z_stream *zs;
255210284Sjmallett
256210284Sjmallett	CHECK_OBJ_NOTNULL(fr, FIFOLOG_READER_MAGIC);
257210284Sjmallett	zs = fr->ff->zs;
258210284Sjmallett	lseq = 0;
259210284Sjmallett	while (1) {
260210284Sjmallett		e = fifolog_int_read(fr->ff, o);
261210284Sjmallett		if (e)
262210284Sjmallett			err(1, "Read error (%d)", e);
263210284Sjmallett		if (++o >= fr->ff->logsize)
264210284Sjmallett			o = 0;
265210284Sjmallett		seq = be32dec(fr->ff->recbuf);
266210284Sjmallett		if (lseq != 0 && seq != lseq + 1)
267210284Sjmallett			break;
268210284Sjmallett		lseq = seq;
269210284Sjmallett		zs->avail_in = fr->ff->recsize - 5;
270210284Sjmallett		zs->next_in = fr->ff->recbuf + 5;
271210284Sjmallett		if (fr->ff->recbuf[4] & FIFOLOG_FLG_1BYTE)
272210284Sjmallett			zs->avail_in -= fr->ff->recbuf[fr->ff->recsize - 1];
273210284Sjmallett		if (fr->ff->recbuf[4] & FIFOLOG_FLG_4BYTE)
274210284Sjmallett			zs->avail_in -=
275210284Sjmallett			    be32dec(fr->ff->recbuf + fr->ff->recsize - 4);
276210284Sjmallett		if (fr->ff->recbuf[4] & FIFOLOG_FLG_SYNC) {
277210284Sjmallett			i = inflateReset(zs);
278210284Sjmallett			assert(i == Z_OK);
279210284Sjmallett			zs->next_out = fr->obuf;
280210284Sjmallett			zs->avail_out = fr->olen;
281210284Sjmallett			t = be32dec(fr->ff->recbuf + 5);
282210284Sjmallett			if (t > end)
283210284Sjmallett				break;
284210284Sjmallett			zs->next_in += 4;
285210284Sjmallett			zs->avail_in -= 4;
286210284Sjmallett		}
287210284Sjmallett
288210284Sjmallett		while(zs->avail_in > 0) {
289210284Sjmallett			i = inflate(zs, 0);
290210284Sjmallett			if (i == Z_BUF_ERROR) {
291210284Sjmallett#if 1
292210284Sjmallett				fprintf(stderr,
293210284Sjmallett				    "Z_BUF_ERROR [%d,%d] [%d,%d,%d]\n",
294210284Sjmallett				    (int)(zs->next_in - fr->ff->recbuf),
295210284Sjmallett				    zs->avail_in,
296210284Sjmallett				    (int)(zs->next_out - fr->obuf),
297210284Sjmallett				    zs->avail_out, fr->olen);
298210284Sjmallett				exit (250);
299210284Sjmallett#else
300210284Sjmallett
301210284Sjmallett				i = Z_OK;
302210284Sjmallett#endif
303210284Sjmallett			}
304210284Sjmallett			if (i == Z_STREAM_END) {
305210284Sjmallett				i = inflateReset(zs);
306210284Sjmallett			}
307210284Sjmallett			if (i != Z_OK) {
308210284Sjmallett				fprintf(stderr, "inflate = %d\n", i);
309210284Sjmallett				exit (250);
310210284Sjmallett			}
311210284Sjmallett			assert(i == Z_OK);
312210284Sjmallett			if (zs->avail_out != fr->olen) {
313210284Sjmallett				q = fr->obuf + (fr->olen - zs->avail_out);
314210284Sjmallett				p = fifolog_reader_chop(fr, func, priv);
315210284Sjmallett				if (p < q)
316210284Sjmallett					(void)memmove(fr->obuf, p, q - p);
317210284Sjmallett				zs->avail_out = fr->olen - (q - p);
318210284Sjmallett				zs->next_out = fr->obuf + (q - p);
319210284Sjmallett			}
320210284Sjmallett		}
321210284Sjmallett	}
322210284Sjmallett}
323210284Sjmallett