1176998Sphk/*- 2176998Sphk * Copyright (c) 2005-2008 Poul-Henning Kamp 3176998Sphk * All rights reserved. 4176998Sphk * 5176998Sphk * Redistribution and use in source and binary forms, with or without 6176998Sphk * modification, are permitted provided that the following conditions 7176998Sphk * are met: 8176998Sphk * 1. Redistributions of source code must retain the above copyright 9176998Sphk * notice, this list of conditions and the following disclaimer. 10176998Sphk * 2. Redistributions in binary form must reproduce the above copyright 11176998Sphk * notice, this list of conditions and the following disclaimer in the 12176998Sphk * documentation and/or other materials provided with the distribution. 13176998Sphk * 14176998Sphk * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15176998Sphk * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16176998Sphk * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17176998Sphk * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18176998Sphk * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19176998Sphk * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20176998Sphk * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21176998Sphk * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22176998Sphk * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23176998Sphk * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24176998Sphk * SUCH DAMAGE. 25176998Sphk * 26176998Sphk * $FreeBSD: stable/10/usr.sbin/fifolog/lib/fifolog_reader.c 306910 2016-10-09 19:58:27Z pfg $ 27176998Sphk */ 28176998Sphk 29176998Sphk#include <stdio.h> 30176998Sphk#include <unistd.h> 31176998Sphk#include <assert.h> 32176998Sphk#include <err.h> 33176998Sphk#include <time.h> 34176998Sphk#include <string.h> 35176998Sphk#include <stdlib.h> 36176998Sphk#include <zlib.h> 37176998Sphk#include <sys/endian.h> 38176998Sphk 39176998Sphk#include "fifolog.h" 40176998Sphk#include "libfifolog.h" 41176998Sphk#include "libfifolog_int.h" 42176998Sphk#include "miniobj.h" 43176998Sphk 44176998Sphk/*--------------------------------------------------------------------*/ 45176998Sphk 46176998Sphkstruct fifolog_reader { 47176998Sphk unsigned magic; 48176998Sphk#define FIFOLOG_READER_MAGIC 0x1036d139 49176998Sphk struct fifolog_file *ff; 50176998Sphk unsigned olen; 51219027Sphk unsigned char *obuf; 52176998Sphk time_t now; 53176998Sphk}; 54176998Sphk 55176998Sphkstruct fifolog_reader * 56176998Sphkfifolog_reader_open(const char *fname) 57176998Sphk{ 58176998Sphk const char *retval; 59176998Sphk struct fifolog_reader *fr; 60176998Sphk int i; 61176998Sphk 62176998Sphk fr = calloc(sizeof *fr, 1); 63176998Sphk if (fr == NULL) 64176998Sphk err(1, "Cannot malloc"); 65176998Sphk 66176998Sphk retval = fifolog_int_open(&fr->ff, fname, 0); 67176998Sphk if (retval != NULL) 68176998Sphk err(1, "%s", retval); 69176998Sphk 70306910Spfg fr->obuf = calloc(16, fr->ff->recsize); 71176998Sphk if (fr->obuf == NULL) 72176998Sphk err(1, "Cannot malloc"); 73306910Spfg fr->olen = fr->ff->recsize * 16; 74176998Sphk 75176998Sphk i = inflateInit(fr->ff->zs); 76176998Sphk assert(i == Z_OK); 77176998Sphk 78219027Sphk fr->magic = FIFOLOG_READER_MAGIC; 79176998Sphk return (fr); 80176998Sphk} 81176998Sphk 82176998Sphk/* 83176998Sphk * Find the next SYNC block 84176998Sphk * 85176998Sphk * Return: 86176998Sphk * 0 - empty fifolog 87176998Sphk * 1 - found sync block 88176998Sphk * 2 - would have wrapped around 89176998Sphk * 3 - End of written log. 90176998Sphk */ 91176998Sphk 92176998Sphkstatic int 93176998Sphkfifolog_reader_findsync(const struct fifolog_file *ff, off_t *o) 94176998Sphk{ 95176998Sphk int e; 96176998Sphk unsigned seq, seqs; 97176998Sphk 98176998Sphk assert(*o < ff->logsize); 99176998Sphk e = fifolog_int_read(ff, *o); 100176998Sphk if (e) 101185790Sphk err(1, "Read error (%d) while looking for SYNC", e); 102176998Sphk seq = be32dec(ff->recbuf); 103176998Sphk if (*o == 0 && seq == 0) 104176998Sphk return (0); 105176998Sphk 106176998Sphk if (ff->recbuf[4] & FIFOLOG_FLG_SYNC) 107176998Sphk return (1); /* That was easy... */ 108176998Sphk while(1) { 109176998Sphk assert(*o < ff->logsize); 110176998Sphk (*o)++; 111176998Sphk seq++; 112176998Sphk if (*o == ff->logsize) 113176998Sphk return (2); /* wraparound */ 114176998Sphk e = fifolog_int_read(ff, *o); 115176998Sphk if (e) 116185790Sphk err(1, "Read error (%d) while looking for SYNC", e); 117176998Sphk seqs = be32dec(ff->recbuf); 118176998Sphk if (seqs != seq) 119176998Sphk return (3); /* End of log */ 120176998Sphk if (ff->recbuf[4] & FIFOLOG_FLG_SYNC) 121176998Sphk return (1); /* Bingo! */ 122176998Sphk } 123176998Sphk} 124176998Sphk 125176998Sphk/* 126176998Sphk * Seek out a given timestamp 127176998Sphk */ 128176998Sphk 129176998Sphkoff_t 130176998Sphkfifolog_reader_seek(const struct fifolog_reader *fr, time_t t0) 131176998Sphk{ 132176998Sphk off_t o, s, st; 133176998Sphk time_t t, tt; 134176998Sphk unsigned seq, seqs; 135176998Sphk const char *retval; 136176998Sphk int e; 137176998Sphk 138176998Sphk CHECK_OBJ_NOTNULL(fr, FIFOLOG_READER_MAGIC); 139176998Sphk 140176998Sphk /* 141176998Sphk * First, find the first SYNC block 142176998Sphk */ 143176998Sphk o = 0; 144176998Sphk e = fifolog_reader_findsync(fr->ff, &o); 145176998Sphk if (e == 0) 146176998Sphk return (0); /* empty fifolog */ 147219027Sphk assert(e == 1); 148176998Sphk 149176998Sphk assert(fr->ff->recbuf[4] & FIFOLOG_FLG_SYNC); 150176998Sphk seq = be32dec(fr->ff->recbuf); 151176998Sphk t = be32dec(fr->ff->recbuf + 5); 152176998Sphk 153176998Sphk if (t > t0) { 154176998Sphk /* Check if there is a second older part we can use */ 155176998Sphk retval = fifolog_int_findend(fr->ff, &s); 156176998Sphk if (retval != NULL) 157176998Sphk err(1, "%s", retval); 158188008Sphk s++; 159176998Sphk e = fifolog_reader_findsync(fr->ff, &s); 160176998Sphk if (e == 0) 161176998Sphk return (0); /* empty fifolog */ 162176998Sphk if (e == 1) { 163176998Sphk o = s; 164176998Sphk seq = be32dec(fr->ff->recbuf); 165176998Sphk t = be32dec(fr->ff->recbuf + 5); 166176998Sphk } 167176998Sphk } 168176998Sphk 169176998Sphk /* Now do a binary search to find the sync block right before t0 */ 170176998Sphk s = st = (fr->ff->logsize - o) / 2; 171176998Sphk while (s > 1) { 172176998Sphk /* We know we shouldn't wrap */ 173176998Sphk if (o + st > fr->ff->logsize + 1) { 174176998Sphk s = st = s / 2; 175176998Sphk continue; 176176998Sphk } 177176998Sphk e = fifolog_int_read(fr->ff, o + st); 178185790Sphk if (e) { 179185790Sphk s = st = s / 2; 180185790Sphk continue; 181185790Sphk } 182176998Sphk /* If not in same part, sequence won't match */ 183176998Sphk seqs = be32dec(fr->ff->recbuf); 184176998Sphk if (seqs != seq + st) { 185176998Sphk s = st = s / 2; 186176998Sphk continue; 187176998Sphk } 188176998Sphk /* If not sync block, try next */ 189176998Sphk if (!(fr->ff->recbuf[4] & FIFOLOG_FLG_SYNC)) { 190176998Sphk st++; 191176998Sphk continue; 192176998Sphk } 193176998Sphk /* Check timestamp */ 194176998Sphk tt = be32dec(fr->ff->recbuf + 5); 195176998Sphk if (tt >= t0) { 196176998Sphk s = st = s / 2; 197176998Sphk continue; 198176998Sphk } 199176998Sphk o += st; 200176998Sphk seq = seqs; 201176998Sphk } 202176998Sphk fprintf(stderr, "Read from %jx\n", o * fr->ff->recsize); 203176998Sphk return (o); 204176998Sphk} 205176998Sphk 206176998Sphkstatic unsigned char * 207176998Sphkfifolog_reader_chop(struct fifolog_reader *fr, fifolog_reader_render_t *func, void *priv) 208176998Sphk{ 209176998Sphk u_char *p, *q; 210176998Sphk uint32_t v, w, u; 211176998Sphk 212176998Sphk p = fr->obuf; 213176998Sphk q = fr->obuf + (fr->olen - fr->ff->zs->avail_out); 214176998Sphk 215176998Sphk while (1) { 216176998Sphk /* Make sure we have a complete header */ 217176998Sphk if (p + 5 >= q) 218176998Sphk return (p); 219176998Sphk w = 4; 220176998Sphk u = be32dec(p); 221176998Sphk if (u & FIFOLOG_TIMESTAMP) { 222176998Sphk fr->now = be32dec(p + 4); 223176998Sphk w += 4; 224176998Sphk } 225176998Sphk if (u & FIFOLOG_LENGTH) { 226176998Sphk v = p[w]; 227176998Sphk w++; 228208110Sphk if (p + w + v >= q) 229208110Sphk return (p); 230176998Sphk } else { 231176998Sphk for (v = 0; p + v + w < q && p[v + w] != '\0'; v++) 232176998Sphk continue; 233176998Sphk if (p + v + w >= q) 234176998Sphk return (p); 235176998Sphk v++; 236176998Sphk } 237176998Sphk func(priv, fr->now, u, p + w, v); 238176998Sphk p += w + v; 239176998Sphk } 240176998Sphk} 241176998Sphk 242176998Sphk/* 243176998Sphk * Process fifolog until end of written log or provided timestamp 244176998Sphk */ 245176998Sphk 246176998Sphkvoid 247176998Sphkfifolog_reader_process(struct fifolog_reader *fr, off_t from, fifolog_reader_render_t *func, void *priv, time_t end) 248176998Sphk{ 249176998Sphk uint32_t seq, lseq; 250176998Sphk off_t o = from; 251176998Sphk int i, e; 252176998Sphk time_t t; 253176998Sphk u_char *p, *q; 254176998Sphk z_stream *zs; 255176998Sphk 256176998Sphk CHECK_OBJ_NOTNULL(fr, FIFOLOG_READER_MAGIC); 257176998Sphk zs = fr->ff->zs; 258176998Sphk lseq = 0; 259176998Sphk while (1) { 260176998Sphk e = fifolog_int_read(fr->ff, o); 261176998Sphk if (e) 262185790Sphk err(1, "Read error (%d)", e); 263176998Sphk if (++o >= fr->ff->logsize) 264176998Sphk o = 0; 265176998Sphk seq = be32dec(fr->ff->recbuf); 266176998Sphk if (lseq != 0 && seq != lseq + 1) 267176998Sphk break; 268176998Sphk lseq = seq; 269176998Sphk zs->avail_in = fr->ff->recsize - 5; 270176998Sphk zs->next_in = fr->ff->recbuf + 5; 271176998Sphk if (fr->ff->recbuf[4] & FIFOLOG_FLG_1BYTE) 272176998Sphk zs->avail_in -= fr->ff->recbuf[fr->ff->recsize - 1]; 273176998Sphk if (fr->ff->recbuf[4] & FIFOLOG_FLG_4BYTE) 274176998Sphk zs->avail_in -= 275176998Sphk be32dec(fr->ff->recbuf + fr->ff->recsize - 4); 276176998Sphk if (fr->ff->recbuf[4] & FIFOLOG_FLG_SYNC) { 277176998Sphk i = inflateReset(zs); 278176998Sphk assert(i == Z_OK); 279176998Sphk zs->next_out = fr->obuf; 280176998Sphk zs->avail_out = fr->olen; 281176998Sphk t = be32dec(fr->ff->recbuf + 5); 282176998Sphk if (t > end) 283176998Sphk break; 284176998Sphk zs->next_in += 4; 285176998Sphk zs->avail_in -= 4; 286176998Sphk } 287176998Sphk 288176998Sphk while(zs->avail_in > 0) { 289176998Sphk i = inflate(zs, 0); 290176998Sphk if (i == Z_BUF_ERROR) { 291176998Sphk#if 1 292176998Sphk fprintf(stderr, 293176998Sphk "Z_BUF_ERROR [%d,%d] [%d,%d,%d]\n", 294176998Sphk (int)(zs->next_in - fr->ff->recbuf), 295176998Sphk zs->avail_in, 296176998Sphk (int)(zs->next_out - fr->obuf), 297176998Sphk zs->avail_out, fr->olen); 298176998Sphk exit (250); 299176998Sphk#else 300219027Sphk 301176998Sphk i = Z_OK; 302176998Sphk#endif 303176998Sphk } 304176998Sphk if (i == Z_STREAM_END) { 305176998Sphk i = inflateReset(zs); 306176998Sphk } 307209871Skeramida if (i != Z_OK) { 308176998Sphk fprintf(stderr, "inflate = %d\n", i); 309209871Skeramida exit (250); 310209871Skeramida } 311176998Sphk assert(i == Z_OK); 312176998Sphk if (zs->avail_out != fr->olen) { 313176998Sphk q = fr->obuf + (fr->olen - zs->avail_out); 314176998Sphk p = fifolog_reader_chop(fr, func, priv); 315219027Sphk if (p < q) 316176998Sphk (void)memmove(fr->obuf, p, q - p); 317176998Sphk zs->avail_out = fr->olen - (q - p); 318176998Sphk zs->next_out = fr->obuf + (q - p); 319176998Sphk } 320176998Sphk } 321176998Sphk } 322176998Sphk} 323