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(1, sizeof(*fr)); 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->obuf = calloc(16, fr->ff->recsize); 71 if (fr->obuf == NULL) 72 err(1, "Cannot malloc"); 73 fr->olen = fr->ff->recsize * 16; 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 s++; 159 e = fifolog_reader_findsync(fr->ff, &s); 160 if (e == 0) 161 return (0); /* empty fifolog */ 162 if (e == 1) { 163 o = s; 164 seq = be32dec(fr->ff->recbuf); 165 t = be32dec(fr->ff->recbuf + 5); 166 } 167 } 168 169 /* Now do a binary search to find the sync block right before t0 */ 170 s = st = (fr->ff->logsize - o) / 2; 171 while (s > 1) { 172 /* We know we shouldn't wrap */ 173 if (o + st > fr->ff->logsize + 1) { 174 s = st = s / 2; 175 continue; 176 } 177 e = fifolog_int_read(fr->ff, o + st); 178 if (e) { 179 s = st = s / 2; 180 continue; 181 } 182 /* If not in same part, sequence won't match */ 183 seqs = be32dec(fr->ff->recbuf); 184 if (seqs != seq + st) { 185 s = st = s / 2; 186 continue; 187 } 188 /* If not sync block, try next */ 189 if (!(fr->ff->recbuf[4] & FIFOLOG_FLG_SYNC)) { 190 st++; 191 continue; 192 } 193 /* Check timestamp */ 194 tt = be32dec(fr->ff->recbuf + 5); 195 if (tt >= t0) { 196 s = st = s / 2; 197 continue; 198 } 199 o += st; 200 seq = seqs; 201 } 202 fprintf(stderr, "Read from %jx\n", o * fr->ff->recsize); 203 return (o); 204 } 205 206 static unsigned char * 207 fifolog_reader_chop(struct fifolog_reader *fr, fifolog_reader_render_t *func, void *priv) 208 { 209 u_char *p, *q; 210 uint32_t v, w, u; 211 212 p = fr->obuf; 213 q = fr->obuf + (fr->olen - fr->ff->zs->avail_out); 214 215 while (1) { 216 /* Make sure we have a complete header */ 217 if (p + 5 >= q) 218 return (p); 219 w = 4; 220 u = be32dec(p); 221 if (u & FIFOLOG_TIMESTAMP) { 222 fr->now = be32dec(p + 4); 223 w += 4; 224 } 225 if (u & FIFOLOG_LENGTH) { 226 v = p[w]; 227 w++; 228 if (p + w + v >= q) 229 return (p); 230 } else { 231 for (v = 0; p + v + w < q && p[v + w] != '\0'; v++) 232 continue; 233 if (p + v + w >= q) 234 return (p); 235 v++; 236 } 237 func(priv, fr->now, u, p + w, v); 238 p += w + v; 239 } 240 } 241 242 /* 243 * Process fifolog until end of written log or provided timestamp 244 */ 245 246 void 247 fifolog_reader_process(struct fifolog_reader *fr, off_t from, fifolog_reader_render_t *func, void *priv, time_t end) 248 { 249 uint32_t seq, lseq; 250 off_t o = from; 251 int i, e; 252 time_t t; 253 u_char *p, *q; 254 z_stream *zs; 255 256 CHECK_OBJ_NOTNULL(fr, FIFOLOG_READER_MAGIC); 257 zs = fr->ff->zs; 258 lseq = 0; 259 while (1) { 260 e = fifolog_int_read(fr->ff, o); 261 if (e) 262 err(1, "Read error (%d)", e); 263 if (++o >= fr->ff->logsize) 264 o = 0; 265 seq = be32dec(fr->ff->recbuf); 266 if (lseq != 0 && seq != lseq + 1) 267 break; 268 lseq = seq; 269 zs->avail_in = fr->ff->recsize - 5; 270 zs->next_in = fr->ff->recbuf + 5; 271 if (fr->ff->recbuf[4] & FIFOLOG_FLG_1BYTE) 272 zs->avail_in -= fr->ff->recbuf[fr->ff->recsize - 1]; 273 if (fr->ff->recbuf[4] & FIFOLOG_FLG_4BYTE) 274 zs->avail_in -= 275 be32dec(fr->ff->recbuf + fr->ff->recsize - 4); 276 if (fr->ff->recbuf[4] & FIFOLOG_FLG_SYNC) { 277 i = inflateReset(zs); 278 assert(i == Z_OK); 279 zs->next_out = fr->obuf; 280 zs->avail_out = fr->olen; 281 t = be32dec(fr->ff->recbuf + 5); 282 if (t > end) 283 break; 284 zs->next_in += 4; 285 zs->avail_in -= 4; 286 } 287 288 while(zs->avail_in > 0) { 289 i = inflate(zs, 0); 290 if (i == Z_BUF_ERROR) { 291 #if 1 292 fprintf(stderr, 293 "Z_BUF_ERROR [%d,%d] [%d,%d,%d]\n", 294 (int)(zs->next_in - fr->ff->recbuf), 295 zs->avail_in, 296 (int)(zs->next_out - fr->obuf), 297 zs->avail_out, fr->olen); 298 exit (250); 299 #else 300 301 i = Z_OK; 302 #endif 303 } 304 if (i == Z_STREAM_END) { 305 i = inflateReset(zs); 306 } 307 if (i != Z_OK) { 308 fprintf(stderr, "inflate = %d\n", i); 309 exit (250); 310 } 311 assert(i == Z_OK); 312 if (zs->avail_out != fr->olen) { 313 q = fr->obuf + (fr->olen - zs->avail_out); 314 p = fifolog_reader_chop(fr, func, priv); 315 if (p < q) 316 (void)memmove(fr->obuf, p, q - p); 317 zs->avail_out = fr->olen - (q - p); 318 zs->next_out = fr->obuf + (q - p); 319 } 320 } 321 } 322 } 323