1 /*- 2 * Copyright (c) 2005-2008 Poul-Henning Kamp 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $FreeBSD$ 27 */ 28 29 #include <stdio.h> 30 #include <unistd.h> 31 #include <assert.h> 32 #include <err.h> 33 #include <time.h> 34 #include <string.h> 35 #include <stdlib.h> 36 #include <zlib.h> 37 #include <sys/endian.h> 38 39 #include "fifolog.h" 40 #include "libfifolog.h" 41 #include "libfifolog_int.h" 42 #include "miniobj.h" 43 44 /*--------------------------------------------------------------------*/ 45 46 struct fifolog_reader { 47 unsigned magic; 48 #define FIFOLOG_READER_MAGIC 0x1036d139 49 struct fifolog_file *ff; 50 unsigned olen; 51 unsigned char *obuf; 52 time_t now; 53 }; 54 55 struct fifolog_reader * 56 fifolog_reader_open(const char *fname) 57 { 58 const char *retval; 59 struct fifolog_reader *fr; 60 int i; 61 62 fr = calloc(sizeof *fr, 1); 63 if (fr == NULL) 64 err(1, "Cannot malloc"); 65 66 retval = fifolog_int_open(&fr->ff, fname, 0); 67 if (retval != NULL) 68 err(1, "%s", retval); 69 70 fr->olen = fr->ff->recsize * 16; 71 fr->obuf = calloc(fr->olen, 1); 72 if (fr->obuf == NULL) 73 err(1, "Cannot malloc"); 74 75 i = inflateInit(fr->ff->zs); 76 assert(i == Z_OK); 77 78 fr->magic = FIFOLOG_READER_MAGIC; 79 return (fr); 80 } 81 82 /* 83 * Find the next SYNC block 84 * 85 * Return: 86 * 0 - empty fifolog 87 * 1 - found sync block 88 * 2 - would have wrapped around 89 * 3 - End of written log. 90 */ 91 92 static int 93 fifolog_reader_findsync(const struct fifolog_file *ff, off_t *o) 94 { 95 int e; 96 unsigned seq, seqs; 97 98 assert(*o < ff->logsize); 99 e = fifolog_int_read(ff, *o); 100 if (e) 101 err(1, "Read error (%d) while looking for SYNC", e); 102 seq = be32dec(ff->recbuf); 103 if (*o == 0 && seq == 0) 104 return (0); 105 106 if (ff->recbuf[4] & FIFOLOG_FLG_SYNC) 107 return (1); /* That was easy... */ 108 while(1) { 109 assert(*o < ff->logsize); 110 (*o)++; 111 seq++; 112 if (*o == ff->logsize) 113 return (2); /* wraparound */ 114 e = fifolog_int_read(ff, *o); 115 if (e) 116 err(1, "Read error (%d) while looking for SYNC", e); 117 seqs = be32dec(ff->recbuf); 118 if (seqs != seq) 119 return (3); /* End of log */ 120 if (ff->recbuf[4] & FIFOLOG_FLG_SYNC) 121 return (1); /* Bingo! */ 122 } 123 } 124 125 /* 126 * Seek out a given timestamp 127 */ 128 129 off_t 130 fifolog_reader_seek(const struct fifolog_reader *fr, time_t t0) 131 { 132 off_t o, s, st; 133 time_t t, tt; 134 unsigned seq, seqs; 135 const char *retval; 136 int e; 137 138 CHECK_OBJ_NOTNULL(fr, FIFOLOG_READER_MAGIC); 139 140 /* 141 * First, find the first SYNC block 142 */ 143 o = 0; 144 e = fifolog_reader_findsync(fr->ff, &o); 145 if (e == 0) 146 return (0); /* empty fifolog */ 147 assert(e == 1); 148 149 assert(fr->ff->recbuf[4] & FIFOLOG_FLG_SYNC); 150 seq = be32dec(fr->ff->recbuf); 151 t = be32dec(fr->ff->recbuf + 5); 152 153 if (t > t0) { 154 /* Check if there is a second older part we can use */ 155 retval = fifolog_int_findend(fr->ff, &s); 156 if (retval != NULL) 157 err(1, "%s", retval); 158 e = fifolog_reader_findsync(fr->ff, &s); 159 if (e == 0) 160 return (0); /* empty fifolog */ 161 if (e == 1) { 162 o = s; 163 seq = be32dec(fr->ff->recbuf); 164 t = be32dec(fr->ff->recbuf + 5); 165 } 166 } 167 168 /* Now do a binary search to find the sync block right before t0 */ 169 s = st = (fr->ff->logsize - o) / 2; 170 while (s > 1) { 171 /* We know we shouldn't wrap */ 172 if (o + st > fr->ff->logsize + 1) { 173 s = st = s / 2; 174 continue; 175 } 176 e = fifolog_int_read(fr->ff, o + st); 177 if (e) { 178 s = st = s / 2; 179 continue; 180 } 181 /* If not in same part, sequence won't match */ 182 seqs = be32dec(fr->ff->recbuf); 183 if (seqs != seq + st) { 184 s = st = s / 2; 185 continue; 186 } 187 /* If not sync block, try next */ 188 if (!(fr->ff->recbuf[4] & FIFOLOG_FLG_SYNC)) { 189 st++; 190 continue; 191 } 192 /* Check timestamp */ 193 tt = be32dec(fr->ff->recbuf + 5); 194 if (tt >= t0) { 195 s = st = s / 2; 196 continue; 197 } 198 o += st; 199 seq = seqs; 200 } 201 fprintf(stderr, "Read from %jx\n", o * fr->ff->recsize); 202 return (o); 203 } 204 205 static unsigned char * 206 fifolog_reader_chop(struct fifolog_reader *fr, fifolog_reader_render_t *func, void *priv) 207 { 208 u_char *p, *q; 209 uint32_t v, w, u; 210 211 p = fr->obuf; 212 q = fr->obuf + (fr->olen - fr->ff->zs->avail_out); 213 214 while (1) { 215 /* Make sure we have a complete header */ 216 if (p + 5 >= q) 217 return (p); 218 w = 4; 219 u = be32dec(p); 220 if (u & FIFOLOG_TIMESTAMP) { 221 fr->now = be32dec(p + 4); 222 w += 4; 223 } 224 if (u & FIFOLOG_LENGTH) { 225 v = p[w]; 226 w++; 227 } else { 228 for (v = 0; p + v + w < q && p[v + w] != '\0'; v++) 229 continue; 230 if (p + v + w >= q) 231 return (p); 232 v++; 233 } 234 func(priv, fr->now, u, p + w, v); 235 p += w + v; 236 } 237 } 238 239 /* 240 * Process fifolog until end of written log or provided timestamp 241 */ 242 243 void 244 fifolog_reader_process(struct fifolog_reader *fr, off_t from, fifolog_reader_render_t *func, void *priv, time_t end) 245 { 246 uint32_t seq, lseq; 247 off_t o = from; 248 int i, e; 249 time_t t; 250 u_char *p, *q; 251 z_stream *zs; 252 253 CHECK_OBJ_NOTNULL(fr, FIFOLOG_READER_MAGIC); 254 zs = fr->ff->zs; 255 lseq = 0; 256 while (1) { 257 e = fifolog_int_read(fr->ff, o); 258 if (e) 259 err(1, "Read error (%d)", e); 260 if (++o >= fr->ff->logsize) 261 o = 0; 262 seq = be32dec(fr->ff->recbuf); 263 if (lseq != 0 && seq != lseq + 1) 264 break; 265 lseq = seq; 266 zs->avail_in = fr->ff->recsize - 5; 267 zs->next_in = fr->ff->recbuf + 5; 268 if (fr->ff->recbuf[4] & FIFOLOG_FLG_1BYTE) 269 zs->avail_in -= fr->ff->recbuf[fr->ff->recsize - 1]; 270 if (fr->ff->recbuf[4] & FIFOLOG_FLG_4BYTE) 271 zs->avail_in -= 272 be32dec(fr->ff->recbuf + fr->ff->recsize - 4); 273 if (fr->ff->recbuf[4] & FIFOLOG_FLG_SYNC) { 274 i = inflateReset(zs); 275 assert(i == Z_OK); 276 zs->next_out = fr->obuf; 277 zs->avail_out = fr->olen; 278 t = be32dec(fr->ff->recbuf + 5); 279 if (t > end) 280 break; 281 zs->next_in += 4; 282 zs->avail_in -= 4; 283 } 284 285 while(zs->avail_in > 0) { 286 i = inflate(zs, 0); 287 if (i == Z_BUF_ERROR) { 288 #if 1 289 fprintf(stderr, 290 "Z_BUF_ERROR [%d,%d] [%d,%d,%d]\n", 291 (int)(zs->next_in - fr->ff->recbuf), 292 zs->avail_in, 293 (int)(zs->next_out - fr->obuf), 294 zs->avail_out, fr->olen); 295 exit (250); 296 #else 297 298 i = Z_OK; 299 #endif 300 } 301 if (i == Z_STREAM_END) { 302 i = inflateReset(zs); 303 } 304 if (i != Z_OK) 305 fprintf(stderr, "inflate = %d\n", i); 306 assert(i == Z_OK); 307 if (zs->avail_out != fr->olen) { 308 q = fr->obuf + (fr->olen - zs->avail_out); 309 p = fifolog_reader_chop(fr, func, priv); 310 if (p < q) 311 (void)memmove(fr->obuf, p, q - p); 312 zs->avail_out = fr->olen - (q - p); 313 zs->next_out = fr->obuf + (q - p); 314 } 315 } 316 } 317 } 318