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