Add the fifolog tools to FreeBSD.

Quoth the man-page:

     Fifologs provide a compact round-robin circular storage for recording
     text and binary information to permanent storage in a bounded and pre-
     dictable fashion, time and space wise.

Not yet connected to the build, but feel free to test & review.
This commit is contained in:
Poul-Henning Kamp 2008-03-09 19:14:36 +00:00
parent 801772ec32
commit 662cb04c25
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=176998
21 changed files with 3132 additions and 0 deletions

10
usr.sbin/fifolog/Makefile Normal file
View File

@ -0,0 +1,10 @@
# $FreeBSD$
VERSION_MAJOR = 1
VERSION_MINOR = 1
SUBDIR = lib fifolog_create fifolog_writer fifolog_reader
.include <bsd.subdir.mk>
test: _SUBDIR

View File

@ -0,0 +1,13 @@
# $FreeBSD$
LIBFIFOLOG = ${.OBJDIR}/../lib/libfifolog.a
WARNS ?= 6
# CFLAGS += -O0 -g
# LINT = flint
# LINTFLAGS = ${.CURDIR}/../flint.lnt -I/usr/include
.include "../Makefile.inc"

View File

@ -0,0 +1,22 @@
# $FreeBSD$
PROG = fifolog_create
CFLAGS += -I${.CURDIR}/../lib
DPADD = ${LIBFIFOLOG} ${LIBUTIL}
LDADD = ${LIBFIFOLOG} -lutil
MAN = fifolog.1
MLINKS += fifolog.1 fifolog_create.1
MLINKS += fifolog.1 fifolog_reader.1
MLINKS += fifolog.1 fifolog_writer.1
.include <bsd.prog.mk>
test: ${PROG}
rm -f /tmp/fifolog.?
./${PROG} /tmp/fifolog.0
./${PROG} -s 10m /tmp/fifolog.1
./${PROG} -l 1k /tmp/fifolog.2
./${PROG} -r 1k /tmp/fifolog.3

View File

@ -0,0 +1,210 @@
.\" Copyright (c) 2008 Poul-Henning Kamp
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" $FreeBSD$
.\"
.Dd Feb 9, 2008
.Os FreeBSD 8.0
.Dt FIFOLOG 1
.Sh NAME
.Nm fifolog_create
.Nd Initialize storage for fifolog
.br
.Nm fifolog_write
.Nd Write data to fifolog
.br
.Nm fifolog_read
.Nd Seek and extract data from fifolog
.Sh SYNOPSIS
.Nm fifolog_create
.Op Fl l Ar record-size
.Op Fl r Ar record-count
.Op Fl s Ar size
.Ar file
.Nm fifolog_reader
.Op Fl t
.Op Fl b Ar tstart
.Op Fl B Ar Tstart
.Op Fl e Ar tend
.Op Fl E Ar Tend
.Op Fl o Ar ofile
.Op Fl R Ar regexp
.Op Fl T Ar timefmt
.Ar file
.Nm fifolog_writer
.Op Fl w Ar write-rate
.Op Fl s Ar sync-rate
.Op Fl z Ar compression
.Ar file
.Sh DESCRIPTION
Fifologs provide a compact round-robin circular storage for
recording text and binary information to permanent storage in a bounded
and predictable fashion, time and space wise.
.Pp
A fifolog can be stored either directly on a disk partition or in a
regular file.
.Pp
The input data stream is encoded, compressed and marked up with
timestamps before it is written to storage, such that it is possible
to seek out a particular time interval in the stored data, without
having to decompress the entire logfile.
.Pp
.Nm Fifolog_create
is used to initialize the first sector of a disk device
or filesystem file to make it a fifolog and should be called only
once.
.Pp
Running
.Nm
on an existing fifolog will reset it so that
.Nm fifolog_reader
and
.Nm fifolog_writer
will not see the previous contents.
(The previos contents is not physically erased, and with a bit
of hand-work, all but the first record can be easily recovered).
.Pp
If the file does not already exist
.Nm
will attempt to create and
.Xr ftruncate 3
it to the specified size, defaulting to 86400 records of 512 bytes
if the
.Fl r ,
.Fl l
or
.Fl s
arguments do not specify otherwise.
.Pp
.Nm Fifolog_writer
will read standard input and write it to the end of the fifolog
according to the parameters given.
.Pp
Writes happen whenever the output buffer is filled with compressed
data or when either of two timers expire, forcing a partially filled
buffer to be written.
.Pp
The first and faster timer,
.Fl w write-rate ,
forces available data to be written
but does not flush and reset the compression dictionary.
This timer is intended to minimize the amount of logdata lost in RAM
in case of a crash and by default it fires 10 seconds after
the previous write.
.Pp
The second and slower timer,
.Fl s sync-rate ,
forces a full flush and reset of the compression
engine and causes the next record written to be a synchronization
point with an uncompressed timestamp, making it possible to start
reading the logfile from that record.
By default this timer fires a minute after the previous sync.
.Pp
The
.Fl z compression
argument controls the
.Xr zlib 3
compression level, legal values are zero to nine which is the default.
.Pp
.Nm Fifolog_reader
will retrieve records from the fifolog according to the specified
parameters and write them either to stdout or the file specified
with
.Fl o .
.Pp
It is possible to specify a start and end time to limit the amount
of data
.Nm fifolog_reader
will report.
The lower-case variants
.Fl b
and
.Fl e
take a
.Xr time_t
value, whereas the upper-case variants
.Fl B
and
.Fl E
take human redable specifications such as "1 hour ago".
.Pp
The
.Fl t
argument forces timestamps to be formatted as "YYYYMMDDhhmmss" instead
of as time_t, and
.Fl T
allows the specification of a
.Xr strftime 3
formatting string.
.Pp
Finally, records can be filtered such that only records matching the
(REG_BASIC) regular expression specified with
.Fl R
is output.
.Sh IMPLEMENTATION NOTES
The data stored in the fifolog consists of three layers, an outher
layer that allows searches to synchronization points based on timestamps
without having to decompress and decode the actual contents, a
compression layer implemented with
.Xr zlib 3
and an inner serialization and timestamping layer.
.Pp
The exact encoding is described in the fifolog.h file.
.Pp
Fifolog is particularly well suited for use on Flash based media, where
it results in much lower write-wear, than a filesystem with regular
logfiles rotated with
.Xr newsyslog 8
etc.
.Sh EXAMPLES
Create a fifolog with 1024*1024 records of 512 bytes:
.Bd -literal
fifolog_create -r 10m /tmp/fifolog
.Ed
.Pp
Write a single record to this file:
.Bd -literal
date | fifolog_writer /tmp/fifolog
.Ed
.Pp
Read it back with human readable timestamps:
.Bd -literal
fifolog_reader -t /tmp/fifolog
.Ed
.Pp
One particular useful use of
.Nm fifolog_writer
is with
.Xr syslogd 8
using a line such as this in
.Xr /etc/syslog.conf 5 :
.Bd -literal
*.* |fifolog_writer /var/log/syslog_fifolog
.Ed
.Sh HISTORY
The fifolog tools have been liberated from an open source SCADA applications
called "measured", which monitors and controls remote radio navigation
transmitters for the Danish Air Traffic Control system.
.Sh AUTHORS
The fifolog tools were written by Poul-Henning Kamp

View File

@ -0,0 +1,105 @@
/*-
* Copyright (c) 2005-2008 Poul-Henning Kamp
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#include <stdio.h>
#include <unistd.h>
#include <err.h>
#include <libutil.h>
#include "libfifolog.h"
#define DEF_RECSIZE 512
#define DEF_RECCNT (24 * 60 * 60)
int
main(int argc, char * const *argv)
{
int ch;
int64_t size;
int64_t recsize;
int64_t reccnt;
const char *s;
recsize = 0;
size = 0;
reccnt = 0;
while((ch = getopt(argc, argv, "l:r:s:")) != -1) {
switch (ch) {
case 'l':
if (expand_number(optarg, &recsize))
err(1, "Couldn't parse -l argument");
break;
case 'r':
if (expand_number(optarg, &reccnt))
err(1, "Couldn't parse -r argument");
break;
case 's':
if (expand_number(optarg, &size))
err(1, "Couldn't parse -s argument");
break;
default:
errx(1, "Usage");
}
}
argc -= optind;
argv += optind;
if (argc != 1)
errx(1, "Usage");
if (size != 0 && reccnt != 0 && recsize != 0) { /* N N N */
if (size != reccnt * recsize)
errx(1, "Inconsistent -l, -r and -s values");
} else if (size != 0 && reccnt != 0 && recsize == 0) { /* N N Z */
if (size % reccnt)
errx(1,
"Inconsistent -r and -s values (gives remainder)");
recsize = size / reccnt;
} else if (size != 0 && reccnt == 0 && recsize != 0) { /* N Z N */
if (size % recsize)
errx(1, "-s arg not divisible by -l arg");
} else if (size != 0 && reccnt == 0 && recsize == 0) { /* N Z Z */
recsize = DEF_RECSIZE;
if (size % recsize)
errx(1, "-s arg not divisible by %jd", recsize);
} else if (size == 0 && reccnt != 0 && recsize != 0) { /* Z N N */
size = reccnt * recsize;
} else if (size == 0 && reccnt != 0 && recsize == 0) { /* Z N Z */
recsize = DEF_RECSIZE;
size = reccnt * recsize;
} else if (size == 0 && reccnt == 0 && recsize != 0) { /* Z Z N */
size = DEF_RECCNT * recsize;
} else if (size == 0 && reccnt == 0 && recsize == 0) { /* Z Z Z */
recsize = DEF_RECSIZE;
size = DEF_RECCNT * recsize;
}
s = fifolog_create(argv[0], size, recsize);
if (s == NULL)
return (0);
err(1, "%s", s);
}

View File

@ -0,0 +1,21 @@
# $FreeBSD$
PROG = fifolog_reader
CFLAGS += -I${.CURDIR}/../lib -I${.CURDIR}
NO_MAN = see ../fifolog_create/fifolog.1
DPADD = ${LIBFIFOLOG} ${LIBUTIL} ${LIBZ}
LDADD = ${LIBFIFOLOG} -lutil -lz
.include <bsd.prog.mk>
test: ${PROG}
./${PROG} /tmp/fifolog.0
./${PROG} -t /tmp/fifolog.0
./${PROG} /tmp/fifolog.1
./${PROG} -B "00:00" /tmp/fifolog.1
t2:
./${PROG} -t /critter/10.1.29.74.fifolog

View File

@ -0,0 +1,170 @@
/*-
* Copyright (c) 2005-2008 Poul-Henning Kamp
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#include <stdio.h>
#include <assert.h>
#include <unistd.h>
#include <err.h>
#include <time.h>
#include <string.h>
#include <stdlib.h>
#include <regex.h>
#include "libfifolog.h"
static time_t opt_B;
static time_t opt_E;
static const char *opt_T;
static const char *opt_o;
static const char *opt_R;
static regex_t R;
static FILE *fo;
static void
Render(void *priv __unused, time_t now, unsigned flag __unused, const unsigned char *p, unsigned l __unused)
{
static struct tm utc;
char buf[128];
int i;
if (now < opt_B || now > opt_E)
return;
if (opt_R != NULL && regexec(&R, (const char *)p, 0, NULL, 0))
return;
if (opt_T != NULL) {
(void)gmtime_r(&now, &utc);
i = strftime(buf, sizeof buf, opt_T, &utc);
assert(i > 0);
fprintf(fo, "%s %s\n", buf, p);
} else {
fprintf(fo, "%12ld %s\n", (long)now, p);
}
}
/*--------------------------------------------------------------------*/
static void
Usage(void)
{
fprintf(stderr,
"Usage: fiforead [options] fifofile\n"
"\t-b <start time integer>\n"
"\t-B <start time>\n"
"\t-e <end time integer>\n"
"\t-E <end time>\n"
"\t-o <output file>\n"
"\t-R <regexp> # match regexp\n"
"\t-t # format timestamps as %%Y%%m%%d%%H%%M%%S\n"
"\t-T <timestamp format>\n"
);
exit (2);
}
int
main(int argc, char * const *argv)
{
int ch, i;
off_t o;
struct fifolog_reader *fl;
const char *progname;
progname=argv[0];
time(&opt_E);
opt_o = "-";
while ((ch = getopt(argc, argv, "b:B:e:E:o:R:tT:")) != -1) {
switch (ch) {
case 'b':
opt_B = strtoul(optarg, NULL, 0);
break;
case 'B':
opt_B = get_date(optarg);
if (opt_B == -1)
errx(1, "Didn't understand \"%s\"", optarg);
break;
case 'e':
opt_E = strtoul(optarg, NULL, 0);
break;
case 'E':
opt_E = get_date(optarg);
if (opt_E == -1)
errx(1, "Didn't understand \"%s\"", optarg);
break;
case 'o':
opt_o = optarg;
break;
case 'R':
opt_R = optarg;
break;
case 't':
opt_T = "%Y%m%d%H%M%S";
break;
case 'T':
opt_T = optarg;
break;
default:
Usage();
}
}
argc -= optind;
argv += optind;
if (opt_R != NULL) {
i = regcomp(&R, opt_R, REG_NOSUB);
if (i != 0) {
char buf[BUFSIZ];
(void)regerror(i, &R, buf, sizeof buf);
fprintf(stderr, "-R argument: %s\n", buf);
exit (1);
}
}
fprintf(stderr, "From\t%jd %s", (intmax_t)opt_B, ctime(&opt_B));
fprintf(stderr, "To\t%jd %s", (intmax_t)opt_E, ctime(&opt_E));
if (opt_B >= opt_E)
errx(1, "Begin time not before End time");
if (argv[0] == NULL)
errx(1, "Usage: %s [options] fifolog", progname);
fl = fifolog_reader_open(argv[0]);
if (!strcmp(opt_o, "-"))
fo = stdout;
else {
fo = fopen(opt_o, "w");
if (fo == NULL)
err(1, "Cannot open: %s", argv[1]);
}
o = fifolog_reader_seek(fl, opt_B);
fifolog_reader_process(fl, o, Render, NULL, opt_E);
return (0);
}

View File

@ -0,0 +1,16 @@
# $FreeBSD$
PROG = fifolog_writer
CFLAGS += -I${.CURDIR}/../lib
NO_MAN = see ../fifolog_create/fifolog.1
DPADD = ${LIBFIFOLOG} ${LIBUTIL} ${LIBZ}
LDADD = ${LIBFIFOLOG} -lutil -lz
.include <bsd.prog.mk>
test: ${PROG}
date | ./${PROG} -z 0 /tmp/fifolog.0
lptest 65 | ./${PROG} -z 9 /tmp/fifolog.1

View File

@ -0,0 +1,105 @@
/*-
* Copyright (c) 2005-2008 Poul-Henning Kamp
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#include <stdio.h>
#include <stdlib.h>
#include <err.h>
#include <unistd.h>
#include <ctype.h>
#include <assert.h>
#include <poll.h>
#include <string.h>
#include <zlib.h>
#include "libfifolog.h"
int
main(int argc, char * const *argv)
{
struct fifolog_writer *f;
const char *es;
struct pollfd pfd[1];
char buf[BUFSIZ], *p;
int i, c;
unsigned w_opt = 10;
unsigned s_opt = 60;
unsigned z_opt = Z_BEST_COMPRESSION;
while ((c = getopt(argc, argv, "w:s:z:")) != -1) {
switch(c) {
case 'w':
w_opt = strtoul(optarg, NULL, 0);
break;
case 's':
s_opt = strtoul(optarg, NULL, 0);
break;
case 'z':
z_opt = strtoul(optarg, NULL, 0);
break;
default:
errx(1, "Usage");
}
}
argc -= optind;
argv += optind;
if (argc != 1)
errx(1, "Usage");
if (z_opt > 9)
errx(1, "Usage");
if (w_opt > s_opt)
errx(1, "Usage");
f = fifolog_write_new();
assert(f != NULL);
es = fifolog_write_open(f, argv[0], w_opt, s_opt, z_opt);
if (es)
err(1, "Error: %s", es);
while (1) {
pfd[0].fd = 0;
pfd[0].events = POLLIN;
i = poll(pfd, 1, 1000);
if (i == 1) {
if (fgets(buf, sizeof buf, stdin) == NULL)
break;
p = strchr(buf, '\0');
assert(p != NULL);
while (p > buf && isspace(p[-1]))
p--;
*p = '\0';
if (*buf != '\0')
fifolog_write_bytes_poll(f, 0, 0, buf, 0);
} else if (i == 0)
(void)fifolog_write_poll(f, 0);
}
(void)fifolog_write_flush(f);
return (0);
}

View File

@ -0,0 +1,49 @@
// $FreeBSD$
// FlexeLint file for fifolog tools
//
-passes=3
-ffc
// GCC
-cgnu
+d__FreeBSD__=7
+d__GNUC__=4
+d__GNUC_MINOR__=2
+d__FreeBSD_cc_version=700003
+d__attribute__()=
-d__builtin_va_list=void* // used by stdarg.h
// -d__builtin_stdarg_start()=_to_semi // ditto
// -d__builtin_va_start(a,b)=((void)(b),(a)=0) // ditto
// -d__builtin_va_end()=_to_semi // ditto
+rw(__inline) // enable the (non-standard) __inline keyword
+rw(__inline__) // enable the (non-standard) __inline__ keyword
+d"__unused=/*lint -e{715} -e{818} */"
-e537 // Repeated include file
-elib(652) // #define of symbol '...' declared previously
-function(exit,__assert)
-function(exit,err)
-function(exit,errx)
-e716 // while(1) ...
-e717 // do ... while(0)
// Ignore return values
-esym(534, memset)
-esym(534, memcpy)
-esym(534, strcpy)
-esym(534, printf)
-esym(534, time)
-esym(534, fprintf)
-esym(534, vfprintf)
+libh(fifolog.h)
+libh(miniobj.h)
+libh(libfifolog.h)
-e713 // loss of precision sign/unsigned
-e732 // loss of sign
-e734 // loss of precision assignment
-e737 // loss of sign in promotion int->unsigned
-e573 // sign/unsign mix in divide

View File

@ -0,0 +1,17 @@
# $FreeBSD$
LIB = fifolog
INTERNALLIB = API not published or supported.
SRCS += fifolog_int.c
SRCS += fifolog_create.c
SRCS += fifolog_write_poll.c
SRCS += fifolog_reader.c
SRCS += getdate.y
CFLAGS += -I${.CURDIR}
.include <bsd.lib.mk>
test:
echo ${HAS_EXPAND_NUMBER}

View File

@ -0,0 +1,138 @@
/*-
* Copyright (c) 2005-2008 Poul-Henning Kamp
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#ifndef __LOCAL_FIFOLOG_H_
#define __LOCAL_FIFOLOG_H_
/*
* Definitions for fifolog "protocol": the on-media layout.
*
* The fifolog on-media record has three layers:
* The outher timestamping and synchronization layer.
* The zlib implemented data compression
* The inner sequencing and identification layer.
*
* All three layers are synchronized at a subset of the outher layer
* record boundaries, from where reading can be initiated.
*
*
* The outher layer:
* -----------------
* The first record in a fifolog contains a magic string and version
* information along with a 32be encoded recordsize for all records
* in the fifolog, including the first.
* The recordsize is explicit to avoid ambiguities when a media is
* moved from one machine to another.
*
* Each record in the fifolog has the following contents:
* offset type contents
* --------------------------------------------------------------
* 0 32be sequence_number
* The sequence number is randomly chosen for the
* fifolog and increments once for each record written.
* It's precense allow quick identification of the next
* record to be written using a binary search for the
* first place where a discontinuity in the sequence
* numbers occur.
* 4 8 flags (FIFOLOG_FLG_*)
*
* If (flags & (FIFOLOG_FLG_SYNC)) the record is a synchronization point
* at which the inner layers are aligned so that reading can be started
* at this point.
* To enable seeks into the file based on timestamps, a third field is
* present in these records as well:
* 5 32be time_t containing POSIX's understanding of UTC.
*
* These fields are immediately followed by the inner layer payload as
* described below, which has variable length.
*
* If the inner layer payload is shorter than the available space in
* the record, it is padded with zero bytes, and the number of unused
* bytes, including the encoded length thereof is recorded at the end
* of the record as follows:
*
* If (flags & FIFOLOG_FLG_1BYTE)
* n-1 8 number of unused bytes
* else if (flags & FIFOLOG_FLG_4BYTE)
* n-4 32be number of unused bytes
*
*
* The gzip layer
* --------------
* Is just output from zlib, nothing special here. FIFOLOG_FLG_SYNC
* corresponds to Z_FINISH flags to zlib.
* In most cases, the timer will expire before zlib has filled an entire
* record in which case Z_SYNC_FLUSH will be used to force as much as
* possible into the buffer before it is written. This is not marked
* in outher layer (apart from a natural correlation with padding) since
* zlibs data stream handles this without help.
*
*
* The inner layer:
* ----------------
* The inner layer contains data indentification and to the second
* timestamping (the timestamp in the outherlayer only marks the
* first possible timestamp for content in the SYNC record).
*
* offset type contents
* --------------------------------------------------------------
* 0 32be ident
*
* The bottom 30 bits of the identification word are application defined,
* presently unused in the stand-alone fifolog tools, but used in the
* original "measured" application that originated the fifolog format.
* Should for instance syslogd(8) grow native support for fifolog format,
* it could store the message priority here.
*
* If (ident & FIFOLOG_TIMESTAMP) the record is prefixed by:
* 4 32be time_t containing POSIX's understanding of UTC.
*
* Then follows the content, either as a NUL terminated string or as
* a lenght encoded binary sequence:
*
* If (ident & FIFOLOG_LENGTH) the record is prefixed by:
* {0|4} 8 length of binary data
*
*/
/* Magic identification string */
#define FIFOLOG_FMT_MAGIC "Measured FIFOLOG Ver 1.01\n"
/* Offset of the 32be encoded recordsize in the first sector */
#define FIFOLOG_OFF_BS 0x20
#define FIFOLOG_FLG_1BYTE 0x01
#define FIFOLOG_FLG_4BYTE 0x02
#define FIFOLOG_FLG_RESTART 0x40
#define FIFOLOG_FLG_SYNC 0x80
#define FIFOLOG_TIMESTAMP 0x80000000
#define FIFOLOG_LENGTH 0x40000000
#define FIFOLOG_IDENT 0x3fffffff
#endif /* __LOCAL_FIFOLOG_H_ */

View File

@ -0,0 +1,122 @@
/*-
* Copyright (c) 2005-2008 Poul-Henning Kamp
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/endian.h>
#include <sys/stat.h>
#include <sys/disk.h>
#include "fifolog.h"
#include "libfifolog.h"
const char *
fifolog_create(const char *fn, off_t size, unsigned recsize)
{
int i, fd;
unsigned u;
off_t ms;
struct stat st;
char *buf;
int created;
fd = open(fn, O_WRONLY | O_TRUNC | O_EXCL | O_CREAT, 0644);
if (fd < 0) {
created = 0;
fd = open(fn, O_WRONLY);
if (fd < 0)
return ("Could not open");
} else
created = 1;
/* Default sectorsize is 512 */
if (recsize == 0)
recsize = 512;
/* See what we got... */
i = fstat(fd, &st);
assert(i == 0);
if (!S_ISBLK(st.st_mode) &&
!S_ISCHR(st.st_mode) &&
!S_ISREG(st.st_mode)) {
assert(!close (fd));
return ("Wrong file type");
}
if(!created && S_ISREG(st.st_mode)) {
assert(!close (fd));
return ("Wrong file type");
}
/* For raw disk with larger sectors: use 1 sector */
i = ioctl(fd, DIOCGSECTORSIZE, &u);
if (i == 0 && (u > recsize || (recsize % u) != 0))
recsize = u;
/* If no configured size, or too large for disk, use device size */
i = ioctl(fd, DIOCGMEDIASIZE, &ms);
if (i == 0 && (size == 0 || size > ms))
size = ms;
if (size == 0 && S_ISREG(st.st_mode))
size = st.st_size;
if (size == 0)
size = recsize * (off_t)(24*60*60);
if (S_ISREG(st.st_mode) && ftruncate(fd, size) < 0)
return ("Could not ftrunc");
buf = calloc(recsize, 1);
if (buf == NULL)
return ("Could not malloc");
strcpy(buf, FIFOLOG_FMT_MAGIC); /*lint !e64 */
be32enc(buf + FIFOLOG_OFF_BS, recsize);
if ((int)recsize != pwrite(fd, buf, recsize, 0)) {
i = errno;
free(buf);
errno = i;
return ("Could not write first sector");
}
memset(buf, 0, recsize);
if ((int)recsize != pwrite(fd, buf, recsize, recsize)) {
i = errno;
free(buf);
errno = i;
return ("Could not write second sector");
}
free(buf);
assert(0 == close(fd));
return (NULL);
}

View File

@ -0,0 +1,276 @@
/*-
* Copyright (c) 2005-2008 Poul-Henning Kamp
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <zlib.h>
#include <sys/disk.h>
#include <sys/endian.h>
#include <sys/stat.h>
#include "miniobj.h"
#include "fifolog.h"
#include "libfifolog_int.h"
/*
* Memory handling for zlib
*/
static voidpf
fifo_zalloc(voidpf opaque __unused, uInt items, uInt size)
{
return calloc(items,size);
}
static void
fifo_zfree(voidpf opaque __unused, voidpf address)
{
free(address);
}
/*
* Open a fifolog file or partition for reading or writing.
*
* Return value is NULL for success or a error description string to
* be augmented by errno if non-zero.
*
* The second function is just an error-handling wrapper around the
* first which, does the actual work.
*/
static const char *
fifolog_int_open_i(struct fifolog_file *f, const char *fname, int mode)
{
struct stat st;
unsigned u;
int i;
f->fd = open(fname, mode ? O_RDWR : O_RDONLY);
if (f->fd < 0)
return ("Cannot open");
/* Determine initial record size guesstimate */
i = ioctl(f->fd, DIOCGSECTORSIZE, &f->recsize);
if (i != 0 && errno != ENOTTY)
return ("ioctl(DIOCGSECTORSIZE) failed");
if (i != 0) {
i = fstat(f->fd, &st);
if (!S_ISREG(st.st_mode))
return ("Neither disk nor regular file");
f->recsize = 512;
f->logsize = st.st_size;
} else if (f->recsize < 64) {
return ("Disk device sectorsize smaller than 64");
} else {
i = ioctl(f->fd, DIOCGMEDIASIZE, &f->logsize);
if (i < 0 && errno != ENOTTY)
return ("ioctl(DIOCGMEDIASIZE) failed");
}
/* Allocate a record buffer */
f->recbuf = malloc(f->recsize);
if (f->recbuf == NULL)
return ("Cannot malloc");
/* Read and validate the label sector */
i = pread(f->fd, f->recbuf, f->recsize, 0);
if (i < 0 || i < (int)f->recsize)
return ("Read error, first sector");
errno = 0;
if (memcmp(f->recbuf, FIFOLOG_FMT_MAGIC, strlen(FIFOLOG_FMT_MAGIC) + 1))
return ("Wrong or missing magic string");
u = be32dec(f->recbuf + FIFOLOG_OFF_BS);
if (u < 64)
return ("Wrong record size in header (<64)");
if ((off_t)u >= f->logsize)
return ("Record size in header bigger than fifolog");
f->recsize = u;
/* Reallocate the buffer to correct size if necessary */
if (u != f->recsize) {
free(f->recbuf);
f->recbuf = NULL;
f->recsize = u;
f->recbuf = malloc(f->recsize);
if (f->recbuf == NULL)
return ("Cannot malloc");
}
/* Calculate number of records in fifolog */
f->logsize /= u;
if (f->logsize < 10)
return ("less than 10 records in fifolog");
f->logsize--; /* the label record */
/* Initialize zlib handling */
f->zs = calloc(sizeof *f->zs, 1);
if (f->zs == NULL)
return ("cannot malloc");
f->zs->zalloc = fifo_zalloc;
f->zs->zfree = fifo_zfree;
return (NULL);
}
const char *
fifolog_int_open(struct fifolog_file **ff, const char *fname, int mode)
{
struct fifolog_file fs, *f;
const char *retval;
int e;
f = &fs;
memset(f, 0, sizeof *f);
f->fd = -1;
retval = fifolog_int_open_i(f, fname, mode);
e = errno;
if (retval == NULL) {
*ff = malloc(sizeof *f);
if (*ff != NULL) {
memcpy(*ff, f, sizeof *f);
(*ff)->magic = FIFOLOG_FILE_MAGIC;
return (retval);
}
}
fifolog_int_close(&f);
errno = e;
return (retval);
}
void
fifolog_int_close(struct fifolog_file **ff)
{
struct fifolog_file *f;
f = *ff;
*ff = NULL;
if (f == NULL)
return;
if (f->fd >= 0)
(void)close(f->fd);
if (f->zs != NULL)
free(f->zs);
if (f->recbuf != NULL)
free(f->recbuf);
free(f);
}
static void
fifolog_int_file_assert(const struct fifolog_file *ff)
{
CHECK_OBJ_NOTNULL(ff, FIFOLOG_FILE_MAGIC);
assert(ff->fd >= 0);
assert(ff->recbuf != NULL);
}
/*
* Read a record.
*
* Return zero on success
*/
int
fifolog_int_read(const struct fifolog_file *ff, off_t recno)
{
int i;
fifolog_int_file_assert(ff);
if (recno >= ff->logsize)
return (-1);
recno++; /* label sector */
i = pread(ff->fd, ff->recbuf, ff->recsize, recno * ff->recsize);
if (i < 0)
return (-1);
if (i != (int)ff->recsize)
return (-1);
return (0);
}
/*
* Find the last written record in the fifolog.
*
* Return is error string or NULL on success
*/
const char *
fifolog_int_findend(const struct fifolog_file *ff, off_t *last)
{
off_t o, s;
int e;
unsigned seq0, seq;
fifolog_int_file_assert(ff);
o = 0;
e = fifolog_int_read(ff, o);
if (e)
return("Read error, first record");
seq0 = be32dec(ff->recbuf);
/* If the first records sequence is zero, the fifolog is empty */
if (seq0 == 0) {
*last = o;
return (NULL);
}
/* Do a binary search for a discontinuity in the sequence numbers */
s = ff->logsize / 2;
do {
e = fifolog_int_read(ff, o + s);
if (e)
return ("Read error while searching");
seq = be32dec(ff->recbuf);
if (seq == seq0 + s) {
o += s;
seq0 = seq;
}
s /= 2;
assert(o < ff->logsize);
} while (s > 0);
*last = o;
return (NULL);
}

View File

@ -0,0 +1,315 @@
/*-
* Copyright (c) 2005-2008 Poul-Henning Kamp
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#include <stdio.h>
#include <unistd.h>
#include <assert.h>
#include <err.h>
#include <time.h>
#include <string.h>
#include <stdlib.h>
#include <zlib.h>
#include <sys/endian.h>
#include "fifolog.h"
#include "libfifolog.h"
#include "libfifolog_int.h"
#include "miniobj.h"
/*--------------------------------------------------------------------*/
struct fifolog_reader {
unsigned magic;
#define FIFOLOG_READER_MAGIC 0x1036d139
struct fifolog_file *ff;
unsigned olen;
unsigned char *obuf;
time_t now;
};
struct fifolog_reader *
fifolog_reader_open(const char *fname)
{
const char *retval;
struct fifolog_reader *fr;
int i;
fr = calloc(sizeof *fr, 1);
if (fr == NULL)
err(1, "Cannot malloc");
retval = fifolog_int_open(&fr->ff, fname, 0);
if (retval != NULL)
err(1, "%s", retval);
fr->olen = fr->ff->recsize * 16;
fr->obuf = calloc(fr->olen, 1);
if (fr->obuf == NULL)
err(1, "Cannot malloc");
i = inflateInit(fr->ff->zs);
assert(i == Z_OK);
fr->magic = FIFOLOG_READER_MAGIC;
return (fr);
}
/*
* Find the next SYNC block
*
* Return:
* 0 - empty fifolog
* 1 - found sync block
* 2 - would have wrapped around
* 3 - End of written log.
*/
static int
fifolog_reader_findsync(const struct fifolog_file *ff, off_t *o)
{
int e;
unsigned seq, seqs;
assert(*o < ff->logsize);
e = fifolog_int_read(ff, *o);
if (e)
err(1, "Read error while looking for SYNC");
seq = be32dec(ff->recbuf);
if (*o == 0 && seq == 0)
return (0);
if (ff->recbuf[4] & FIFOLOG_FLG_SYNC)
return (1); /* That was easy... */
while(1) {
assert(*o < ff->logsize);
(*o)++;
seq++;
if (*o == ff->logsize)
return (2); /* wraparound */
e = fifolog_int_read(ff, *o);
if (e)
err(1, "Read error while looking for SYNC");
seqs = be32dec(ff->recbuf);
if (seqs != seq)
return (3); /* End of log */
if (ff->recbuf[4] & FIFOLOG_FLG_SYNC)
return (1); /* Bingo! */
}
}
/*
* Seek out a given timestamp
*/
off_t
fifolog_reader_seek(const struct fifolog_reader *fr, time_t t0)
{
off_t o, s, st;
time_t t, tt;
unsigned seq, seqs;
const char *retval;
int e;
CHECK_OBJ_NOTNULL(fr, FIFOLOG_READER_MAGIC);
/*
* First, find the first SYNC block
*/
o = 0;
e = fifolog_reader_findsync(fr->ff, &o);
if (e == 0)
return (0); /* empty fifolog */
assert(e == 1);
assert(fr->ff->recbuf[4] & FIFOLOG_FLG_SYNC);
seq = be32dec(fr->ff->recbuf);
t = be32dec(fr->ff->recbuf + 5);
if (t > t0) {
/* Check if there is a second older part we can use */
retval = fifolog_int_findend(fr->ff, &s);
if (retval != NULL)
err(1, "%s", retval);
e = fifolog_reader_findsync(fr->ff, &s);
if (e == 0)
return (0); /* empty fifolog */
if (e == 1) {
o = s;
seq = be32dec(fr->ff->recbuf);
t = be32dec(fr->ff->recbuf + 5);
}
}
/* Now do a binary search to find the sync block right before t0 */
s = st = (fr->ff->logsize - o) / 2;
while (s > 1) {
/* We know we shouldn't wrap */
if (o + st > fr->ff->logsize + 1) {
s = st = s / 2;
continue;
}
e = fifolog_int_read(fr->ff, o + st);
if (e)
err(1, "Read error, duing binary search");
/* If not in same part, sequence won't match */
seqs = be32dec(fr->ff->recbuf);
if (seqs != seq + st) {
s = st = s / 2;
continue;
}
/* If not sync block, try next */
if (!(fr->ff->recbuf[4] & FIFOLOG_FLG_SYNC)) {
st++;
continue;
}
/* Check timestamp */
tt = be32dec(fr->ff->recbuf + 5);
if (tt >= t0) {
s = st = s / 2;
continue;
}
o += st;
seq = seqs;
}
fprintf(stderr, "Read from %jx\n", o * fr->ff->recsize);
return (o);
}
static unsigned char *
fifolog_reader_chop(struct fifolog_reader *fr, fifolog_reader_render_t *func, void *priv)
{
u_char *p, *q;
uint32_t v, w, u;
p = fr->obuf;
q = fr->obuf + (fr->olen - fr->ff->zs->avail_out);
while (1) {
/* Make sure we have a complete header */
if (p + 5 >= q)
return (p);
w = 4;
u = be32dec(p);
if (u & FIFOLOG_TIMESTAMP) {
fr->now = be32dec(p + 4);
w += 4;
}
if (u & FIFOLOG_LENGTH) {
v = p[w];
w++;
} else {
for (v = 0; p + v + w < q && p[v + w] != '\0'; v++)
continue;
if (p + v + w >= q)
return (p);
v++;
}
func(priv, fr->now, u, p + w, v);
p += w + v;
}
}
/*
* Process fifolog until end of written log or provided timestamp
*/
void
fifolog_reader_process(struct fifolog_reader *fr, off_t from, fifolog_reader_render_t *func, void *priv, time_t end)
{
uint32_t seq, lseq;
off_t o = from;
int i, e;
time_t t;
u_char *p, *q;
z_stream *zs;
CHECK_OBJ_NOTNULL(fr, FIFOLOG_READER_MAGIC);
zs = fr->ff->zs;
lseq = 0;
while (1) {
e = fifolog_int_read(fr->ff, o);
if (e)
err(1, "Read error");
if (++o >= fr->ff->logsize)
o = 0;
seq = be32dec(fr->ff->recbuf);
if (lseq != 0 && seq != lseq + 1)
break;
lseq = seq;
zs->avail_in = fr->ff->recsize - 5;
zs->next_in = fr->ff->recbuf + 5;
if (fr->ff->recbuf[4] & FIFOLOG_FLG_1BYTE)
zs->avail_in -= fr->ff->recbuf[fr->ff->recsize - 1];
if (fr->ff->recbuf[4] & FIFOLOG_FLG_4BYTE)
zs->avail_in -=
be32dec(fr->ff->recbuf + fr->ff->recsize - 4);
if (fr->ff->recbuf[4] & FIFOLOG_FLG_SYNC) {
i = inflateReset(zs);
assert(i == Z_OK);
zs->next_out = fr->obuf;
zs->avail_out = fr->olen;
t = be32dec(fr->ff->recbuf + 5);
if (t > end)
break;
zs->next_in += 4;
zs->avail_in -= 4;
}
while(zs->avail_in > 0) {
i = inflate(zs, 0);
if (i == Z_BUF_ERROR) {
#if 1
fprintf(stderr,
"Z_BUF_ERROR [%d,%d] [%d,%d,%d]\n",
(int)(zs->next_in - fr->ff->recbuf),
zs->avail_in,
(int)(zs->next_out - fr->obuf),
zs->avail_out, fr->olen);
exit (250);
#else
i = Z_OK;
#endif
}
if (i == Z_STREAM_END) {
i = inflateReset(zs);
}
if (i != Z_OK)
fprintf(stderr, "inflate = %d\n", i);
assert(i == Z_OK);
if (zs->avail_out != fr->olen) {
q = fr->obuf + (fr->olen - zs->avail_out);
p = fifolog_reader_chop(fr, func, priv);
if (p < q)
(void)memmove(fr->obuf, p, q - p);
zs->avail_out = fr->olen - (q - p);
zs->next_out = fr->obuf + (q - p);
}
}
}
}

View File

@ -0,0 +1,65 @@
/*-
* Copyright (c) 2005-2008 Poul-Henning Kamp
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#define FIFOLOG_PT_BYTES_PRE 0
#define FIFOLOG_PT_BYTES_POST 1
#define FIFOLOG_PT_WRITES 2
#define FIFOLOG_PT_FLUSH 3
#define FIFOLOG_PT_SYNC 4
#define FIFOLOG_PT_RUNTIME 5
#define FIFOLOG_NPOINT 6
struct fifolog_writer {
unsigned magic;
#define FIFOLOG_WRITER_MAGIC 0xf1f0706
struct fifolog_file *ff;
unsigned writerate;
unsigned syncrate;
unsigned compression;
unsigned writes_since_sync;
int cleanup;
intmax_t cnt[FIFOLOG_NPOINT];
uint32_t seq;
off_t recno;
int flag;
time_t last;
u_int ibufsize;
u_char *ibuf;
u_char *iptr;
time_t starttime;
time_t lastwrite;
time_t lastsync;
};

View File

@ -0,0 +1,416 @@
/*-
* Copyright (c) 2005-2008 Poul-Henning Kamp
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <sys/endian.h>
#include <zlib.h>
#include "fifolog.h"
#include "libfifolog.h"
#include "libfifolog_int.h"
#include "fifolog_write.h"
#include "miniobj.h"
#define ALLOC(ptr, size) do { \
(*(ptr)) = calloc(size, 1); \
assert(*(ptr) != NULL); \
} while (0)
const char *fifolog_write_statnames[] = {
[FIFOLOG_PT_BYTES_PRE] = "Bytes before compression",
[FIFOLOG_PT_BYTES_POST] = "Bytes after compression",
[FIFOLOG_PT_WRITES] = "Writes",
[FIFOLOG_PT_FLUSH] = "Flushes",
[FIFOLOG_PT_SYNC] = "Syncs",
[FIFOLOG_PT_RUNTIME] = "Runtime"
};
/*
* Check that everything is all right
*/
static void
fifolog_write_assert(const struct fifolog_writer *f)
{
CHECK_OBJ_NOTNULL(f, FIFOLOG_WRITER_MAGIC);
assert(f->iptr == f->ff->zs->next_in + f->ff->zs->avail_in);
assert(f->ff->zs->next_out + f->ff->zs->avail_out == \
f->ff->recbuf + f->ff->recsize);
}
struct fifolog_writer *
fifolog_write_new(void)
{
struct fifolog_writer *f;
ALLOC(&f, sizeof *f);
f->magic = FIFOLOG_WRITER_MAGIC;
return (f);
}
void
fifolog_write_destroy(struct fifolog_writer *f)
{
CHECK_OBJ_NOTNULL(f, FIFOLOG_WRITER_MAGIC);
free(f);
}
void
fifolog_write_close(struct fifolog_writer *f)
{
CHECK_OBJ_NOTNULL(f, FIFOLOG_WRITER_MAGIC);
fifolog_int_close(&f->ff);
if (f->ibuf != NULL)
free(f->ibuf);
free(f);
}
static void
fifo_prepobuf(struct fifolog_writer *f, time_t now, int flag)
{
memset(f->ff->recbuf, 0, f->ff->recsize);
f->ff->zs->next_out = f->ff->recbuf + 5;
f->ff->zs->avail_out = f->ff->recsize - 5;
if (f->recno == 0 && f->seq == 0) {
srandomdev();
do {
f->seq = random();
} while (f->seq == 0);
}
be32enc(f->ff->recbuf, f->seq++);
f->ff->recbuf[4] = f->flag;
f->flag = 0;
if (flag) {
f->ff->recbuf[4] |= FIFOLOG_FLG_SYNC;
be32enc(f->ff->recbuf + 5, (u_int)now);
f->ff->zs->next_out += 4;
f->ff->zs->avail_out -= 4;
}
fifolog_write_assert(f);
}
const char *
fifolog_write_open(struct fifolog_writer *f, const char *fn, unsigned writerate, unsigned syncrate, int compression)
{
const char *es;
int i;
time_t now;
off_t o;
CHECK_OBJ_NOTNULL(f, FIFOLOG_WRITER_MAGIC);
/* Check for legal compression value */
if (compression < Z_DEFAULT_COMPRESSION ||
compression > Z_BEST_COMPRESSION)
return ("Illegal compression value");
f->writerate = writerate;
f->syncrate = syncrate;
f->compression = compression;
/* Reset statistics */
memset(f->cnt, 0, sizeof f->cnt);
es = fifolog_int_open(&f->ff, fn, 1);
if (es != NULL)
return (es);
es = fifolog_int_findend(f->ff, &o);
if (es != NULL)
return (es);
if (o == 0) {
f->seq = 0;
f->recno = 0;
} else {
i = fifolog_int_read(f->ff, o);
if (i)
return ("Read error, looking for seq");
f->seq = be32dec(f->ff->recbuf) + 1;
f->recno = o + 1;
}
f->ibufsize = 32768;
ALLOC(&f->ibuf, f->ibufsize);
f->iptr = f->ibuf;
f->ff->zs->next_in = f->iptr;
i = deflateInit(f->ff->zs, (int)f->compression);
assert(i == Z_OK);
f->flag |= FIFOLOG_FLG_RESTART;
time(&now);
fifo_prepobuf(f, now, 1);
f->starttime = now;
fifolog_write_assert(f);
return (NULL);
}
static void
fifo_writerec(struct fifolog_writer *f)
{
int i;
time_t t;
fifolog_write_assert(f);
f->writes_since_sync++;
assert(f->recno < f->ff->logsize);
f->cnt[FIFOLOG_PT_BYTES_POST] += f->ff->recsize - f->ff->zs->avail_out;
if (f->ff->zs->avail_out == 0) {
/* nothing */
} else if (f->ff->zs->avail_out <= 255) {
f->ff->recbuf[f->ff->recsize - 1] =
(u_char)f->ff->zs->avail_out;
f->ff->recbuf[4] |= FIFOLOG_FLG_1BYTE;
} else {
be32enc(f->ff->recbuf + f->ff->recsize - 4,
f->ff->zs->avail_out);
f->ff->recbuf[4] |= FIFOLOG_FLG_4BYTE;
}
i = pwrite(f->ff->fd, f->ff->recbuf, f->ff->recsize,
(f->recno + 1) * f->ff->recsize);
assert (i == (int)f->ff->recsize);
if (++f->recno == f->ff->logsize)
f->recno = 0;
f->cnt[FIFOLOG_PT_WRITES]++;
time(&t);
f->cnt[FIFOLOG_PT_RUNTIME] = t - f->starttime; /*lint !e776 */
fifolog_write_assert(f);
}
int
fifolog_write_poll(struct fifolog_writer *f, time_t now)
{
int i, fl, bo, bf;
if (now == 0)
time(&now);
fifolog_write_assert(f);
if (f->cleanup || now >= (int)(f->lastsync + f->syncrate)) {
/*
* We always check the sync timer, otherwise a flood of data
* would not get any sync records at all
*/
f->cleanup = 0;
fl = Z_FINISH;
f->lastsync = now;
f->lastwrite = now;
f->cnt[FIFOLOG_PT_SYNC]++;
} else if (f->ff->zs->avail_in == 0 &&
now >= (int)(f->lastwrite + f->writerate)) {
/*
* We only check for writerate timeouts when the input
* buffer is empty. It would be silly to force a write if
* pending input could cause it to happen on its own.
*/
fl = Z_SYNC_FLUSH;
f->lastwrite = now;
f->cnt[FIFOLOG_PT_FLUSH]++;
} else if (f->ff->zs->avail_in == 0)
return (0); /* nothing to do */
else
fl = Z_NO_FLUSH;
for (;;) {
assert(f->ff->zs->avail_out > 0);
bf = f->ff->zs->avail_out;
i = deflate(f->ff->zs, fl);
assert (i == Z_OK || i == Z_BUF_ERROR || i == Z_STREAM_END);
bo = f->ff->zs->avail_out;
/* If we have output space and not in a hurry.. */
if (bo > 0 && fl == Z_NO_FLUSH)
break;
/* Write output buffer, if anything in it */
if (bo != bf)
fifo_writerec(f);
/* If the buffer were full, we need to check again */
if (bo == 0) {
fifo_prepobuf(f, now, 0);
continue;
}
if (fl == Z_FINISH) {
/* Make next record a SYNC record */
fifo_prepobuf(f, now, 1);
/* And reset the zlib engine */
i = deflateReset(f->ff->zs);
assert(i == Z_OK);
f->writes_since_sync = 0;
} else {
fifo_prepobuf(f, now, 0);
}
break;
}
if (f->ff->zs->avail_in == 0) {
/* Reset input buffer when empty */
f->iptr = f->ibuf;
f->ff->zs->next_in = f->iptr;
}
fifolog_write_assert(f);
return (1);
}
static void
fifolog_acct(struct fifolog_writer *f, unsigned bytes)
{
f->ff->zs->avail_in += bytes;
f->iptr += bytes;
f->cnt[FIFOLOG_PT_BYTES_PRE] += bytes;
}
/*
* Attempt to write an entry.
* Return zero if there is no space, one otherwise
*/
int
fifolog_write_bytes(struct fifolog_writer *f, uint32_t id, time_t now, const void *ptr, unsigned len)
{
u_int l;
const unsigned char *p;
fifolog_write_assert(f);
assert(!(id & (FIFOLOG_TIMESTAMP|FIFOLOG_LENGTH)));
assert(ptr != NULL);
if (len == 0) {
len = strlen(ptr);
l = 4 + len; /* id */
p = ptr;
} else {
assert(len <= 255);
p = ptr;
id |= FIFOLOG_LENGTH;
l = 5 + len; /* id + len */
}
l += 4; /* A timestamp may be necessary */
/* Now do timestamp, if needed */
if (now == 0)
time(&now);
assert(l < f->ibufsize);
/* Wait until there is sufficient space without the lock */
if (f->iptr + l > f->ibuf + f->ibufsize)
return (0);
if (now != f->last) {
id |= FIFOLOG_TIMESTAMP;
f->last = now;
}
/* Emit instance+flag and length */
be32enc(f->iptr, id);
fifolog_acct(f, 4);
if (id & FIFOLOG_TIMESTAMP) {
be32enc(f->iptr, (uint32_t)f->last);
fifolog_acct(f, 4);
}
if (id & FIFOLOG_LENGTH) {
f->iptr[0] = (u_char)len;
fifolog_acct(f, 1);
}
assert (len > 0);
memcpy(f->iptr, p, len);
fifolog_acct(f, len);
fifolog_write_assert(f);
return (1);
}
/*
* Write an entry, polling until success.
* Long binary entries are broken into 255 byte chunks.
*/
void
fifolog_write_bytes_poll(struct fifolog_writer *f, uint32_t id, time_t now, const void *ptr, unsigned len)
{
u_int l;
const unsigned char *p;
fifolog_write_assert(f);
assert(!(id & (FIFOLOG_TIMESTAMP|FIFOLOG_LENGTH)));
assert(ptr != NULL);
if (len == 0) {
while (!fifolog_write_bytes(f, id, now, ptr, len)) {
(void)fifolog_write_poll(f, now);
(void)usleep(10000);
}
} else {
p = ptr;
for (p = ptr; len > 0; len -= l, p += l) {
l = len;
if (l > 255)
l = 255;
while (!fifolog_write_bytes(f, id, now, p, l)) {
(void)fifolog_write_poll(f, now);
(void)usleep(10000);
}
}
}
fifolog_write_assert(f);
}
int
fifolog_write_flush(struct fifolog_writer *f)
{
int i;
fifolog_write_assert(f);
f->cleanup = 1;
for (i = 0; fifolog_write_poll(f, 0); i = 1)
continue;
fifolog_write_assert(f);
return (i);
}

View File

@ -0,0 +1,889 @@
%{
/*
** Originally written by Steven M. Bellovin <smb@research.att.com> while
** at the University of North Carolina at Chapel Hill. Later tweaked by
** a couple of people on Usenet. Completely overhauled by Rich $alz
** <rsalz@bbn.com> and Jim Berets <jberets@bbn.com> in August, 1990;
**
** This grammar has 10 shift/reduce conflicts.
**
** This code is in the public domain and has no copyright.
**
** Picked up from CVS and slightly cleaned up by to WARNS=5 level by
** Poul-Henning Kamp <phk@FreeBSD.org>
**
** $FreeBSD$
*/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <sys/types.h>
#include <sys/time.h>
#include "libfifolog.h"
#define yyparse getdate_yyparse
#define yylex getdate_yylex
#define yyerror getdate_yyerror
static int yyparse(void);
static int yylex(void);
static int yyerror(const char *);
#define EPOCH 1970
#define HOUR(x) ((time_t)(x) * 60)
#define SECSPERDAY (24L * 60L * 60L)
/*
** An entry in the lexical lookup table.
*/
typedef struct _TABLE {
const char *name;
int type;
time_t value;
} TABLE;
/*
** Daylight-savings mode: on, off, or not yet known.
*/
typedef enum _DSTMODE {
DSToff, DSTon, DSTmaybe
} DSTMODE;
/*
** Meridian: am, pm, or 24-hour style.
*/
typedef enum _MERIDIAN {
MERam, MERpm, MER24
} MERIDIAN;
/*
** Global variables. We could get rid of most of these by using a good
** union as the yacc stack. (This routine was originally written before
** yacc had the %union construct.) Maybe someday; right now we only use
** the %union very rarely.
*/
static char *yyInput;
static DSTMODE yyDSTmode;
static time_t yyDayOrdinal;
static time_t yyDayNumber;
static int yyHaveDate;
static int yyHaveDay;
static int yyHaveRel;
static int yyHaveTime;
static int yyHaveZone;
static time_t yyTimezone;
static time_t yyDay;
static time_t yyHour;
static time_t yyMinutes;
static time_t yyMonth;
static time_t yySeconds;
static time_t yyYear;
static MERIDIAN yyMeridian;
static time_t yyRelMonth;
static time_t yyRelSeconds;
%}
%union {
time_t Number;
enum _MERIDIAN Meridian;
}
%token tAGO tDAY tDAYZONE tID tMERIDIAN tMINUTE_UNIT tMONTH tMONTH_UNIT
%token tSEC_UNIT tSNUMBER tUNUMBER tZONE tDST
%type <Number> tDAY tDAYZONE tMINUTE_UNIT tMONTH tMONTH_UNIT
%type <Number> tSEC_UNIT tSNUMBER tUNUMBER tZONE
%type <Meridian> tMERIDIAN o_merid
%%
spec : /* NULL */
| spec item
;
item : time {
yyHaveTime++;
}
| zone {
yyHaveZone++;
}
| date {
yyHaveDate++;
}
| day {
yyHaveDay++;
}
| rel {
yyHaveRel++;
}
| cvsstamp {
yyHaveTime++;
yyHaveDate++;
yyHaveZone++;
}
| number
;
cvsstamp: tUNUMBER '.' tUNUMBER '.' tUNUMBER '.' tUNUMBER '.' tUNUMBER '.' tUNUMBER {
yyYear = $1;
if (yyYear < 100) yyYear += 1900;
yyMonth = $3;
yyDay = $5;
yyHour = $7;
yyMinutes = $9;
yySeconds = $11;
yyDSTmode = DSToff;
yyTimezone = 0;
}
;
time : tUNUMBER tMERIDIAN {
yyHour = $1;
yyMinutes = 0;
yySeconds = 0;
yyMeridian = $2;
}
| tUNUMBER ':' tUNUMBER o_merid {
yyHour = $1;
yyMinutes = $3;
yySeconds = 0;
yyMeridian = $4;
}
| tUNUMBER ':' tUNUMBER tSNUMBER {
yyHour = $1;
yyMinutes = $3;
yyMeridian = MER24;
yyDSTmode = DSToff;
yyTimezone = - ($4 % 100 + ($4 / 100) * 60);
}
| tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid {
yyHour = $1;
yyMinutes = $3;
yySeconds = $5;
yyMeridian = $6;
}
| tUNUMBER ':' tUNUMBER ':' tUNUMBER tSNUMBER {
yyHour = $1;
yyMinutes = $3;
yySeconds = $5;
yyMeridian = MER24;
yyDSTmode = DSToff;
yyTimezone = - ($6 % 100 + ($6 / 100) * 60);
}
;
zone : tZONE {
yyTimezone = $1;
yyDSTmode = DSToff;
}
| tDAYZONE {
yyTimezone = $1;
yyDSTmode = DSTon;
}
|
tZONE tDST {
yyTimezone = $1;
yyDSTmode = DSTon;
}
;
day : tDAY {
yyDayOrdinal = 1;
yyDayNumber = $1;
}
| tDAY ',' {
yyDayOrdinal = 1;
yyDayNumber = $1;
}
| tUNUMBER tDAY {
yyDayOrdinal = $1;
yyDayNumber = $2;
}
;
date : tUNUMBER '/' tUNUMBER {
yyMonth = $1;
yyDay = $3;
}
| tUNUMBER '/' tUNUMBER '/' tUNUMBER {
if ($1 >= 100) {
yyYear = $1;
yyMonth = $3;
yyDay = $5;
} else {
yyMonth = $1;
yyDay = $3;
yyYear = $5;
}
}
| tUNUMBER tSNUMBER tSNUMBER {
/* ISO 8601 format. yyyy-mm-dd. */
yyYear = $1;
yyMonth = -$2;
yyDay = -$3;
}
| tUNUMBER tMONTH tSNUMBER {
/* e.g. 17-JUN-1992. */
yyDay = $1;
yyMonth = $2;
yyYear = -$3;
}
| tMONTH tUNUMBER {
yyMonth = $1;
yyDay = $2;
}
| tMONTH tUNUMBER ',' tUNUMBER {
yyMonth = $1;
yyDay = $2;
yyYear = $4;
}
| tUNUMBER tMONTH {
yyMonth = $2;
yyDay = $1;
}
| tUNUMBER tMONTH tUNUMBER {
yyMonth = $2;
yyDay = $1;
yyYear = $3;
}
;
rel : relunit tAGO {
yyRelSeconds = -yyRelSeconds;
yyRelMonth = -yyRelMonth;
}
| relunit
;
relunit : tUNUMBER tMINUTE_UNIT {
yyRelSeconds += $1 * $2 * 60L;
}
| tSNUMBER tMINUTE_UNIT {
yyRelSeconds += $1 * $2 * 60L;
}
| tMINUTE_UNIT {
yyRelSeconds += $1 * 60L;
}
| tSNUMBER tSEC_UNIT {
yyRelSeconds += $1;
}
| tUNUMBER tSEC_UNIT {
yyRelSeconds += $1;
}
| tSEC_UNIT {
yyRelSeconds++;
}
| tSNUMBER tMONTH_UNIT {
yyRelMonth += $1 * $2;
}
| tUNUMBER tMONTH_UNIT {
yyRelMonth += $1 * $2;
}
| tMONTH_UNIT {
yyRelMonth += $1;
}
;
number : tUNUMBER {
if (yyHaveTime && yyHaveDate && !yyHaveRel)
yyYear = $1;
else {
if($1>10000) {
yyHaveDate++;
yyDay= ($1)%100;
yyMonth= ($1/100)%100;
yyYear = $1/10000;
}
else {
yyHaveTime++;
if ($1 < 100) {
yyHour = $1;
yyMinutes = 0;
}
else {
yyHour = $1 / 100;
yyMinutes = $1 % 100;
}
yySeconds = 0;
yyMeridian = MER24;
}
}
}
;
o_merid : /* NULL */ {
$$ = MER24;
}
| tMERIDIAN {
$$ = $1;
}
;
%%
/* Month and day table. */
static TABLE const MonthDayTable[] = {
{ "january", tMONTH, 1 },
{ "february", tMONTH, 2 },
{ "march", tMONTH, 3 },
{ "april", tMONTH, 4 },
{ "may", tMONTH, 5 },
{ "june", tMONTH, 6 },
{ "july", tMONTH, 7 },
{ "august", tMONTH, 8 },
{ "september", tMONTH, 9 },
{ "sept", tMONTH, 9 },
{ "october", tMONTH, 10 },
{ "november", tMONTH, 11 },
{ "december", tMONTH, 12 },
{ "sunday", tDAY, 0 },
{ "monday", tDAY, 1 },
{ "tuesday", tDAY, 2 },
{ "tues", tDAY, 2 },
{ "wednesday", tDAY, 3 },
{ "wednes", tDAY, 3 },
{ "thursday", tDAY, 4 },
{ "thur", tDAY, 4 },
{ "thurs", tDAY, 4 },
{ "friday", tDAY, 5 },
{ "saturday", tDAY, 6 },
{ NULL, 0, 0 }
};
/* Time units table. */
static TABLE const UnitsTable[] = {
{ "year", tMONTH_UNIT, 12 },
{ "month", tMONTH_UNIT, 1 },
{ "fortnight", tMINUTE_UNIT, 14 * 24 * 60 },
{ "week", tMINUTE_UNIT, 7 * 24 * 60 },
{ "day", tMINUTE_UNIT, 1 * 24 * 60 },
{ "hour", tMINUTE_UNIT, 60 },
{ "minute", tMINUTE_UNIT, 1 },
{ "min", tMINUTE_UNIT, 1 },
{ "second", tSEC_UNIT, 1 },
{ "sec", tSEC_UNIT, 1 },
{ NULL, 0, 0 }
};
/* Assorted relative-time words. */
static TABLE const OtherTable[] = {
{ "tomorrow", tMINUTE_UNIT, 1 * 24 * 60 },
{ "yesterday", tMINUTE_UNIT, -1 * 24 * 60 },
{ "today", tMINUTE_UNIT, 0 },
{ "now", tMINUTE_UNIT, 0 },
{ "last", tUNUMBER, -1 },
{ "this", tMINUTE_UNIT, 0 },
{ "next", tUNUMBER, 2 },
{ "first", tUNUMBER, 1 },
/* { "second", tUNUMBER, 2 }, */
{ "third", tUNUMBER, 3 },
{ "fourth", tUNUMBER, 4 },
{ "fifth", tUNUMBER, 5 },
{ "sixth", tUNUMBER, 6 },
{ "seventh", tUNUMBER, 7 },
{ "eighth", tUNUMBER, 8 },
{ "ninth", tUNUMBER, 9 },
{ "tenth", tUNUMBER, 10 },
{ "eleventh", tUNUMBER, 11 },
{ "twelfth", tUNUMBER, 12 },
{ "ago", tAGO, 1 },
{ NULL, 0, 0 }
};
/* The timezone table. */
/* Some of these are commented out because a time_t can't store a float. */
static TABLE const TimezoneTable[] = {
{ "gmt", tZONE, HOUR( 0) }, /* Greenwich Mean */
{ "ut", tZONE, HOUR( 0) }, /* Universal (Coordinated) */
{ "utc", tZONE, HOUR( 0) },
{ "wet", tZONE, HOUR( 0) }, /* Western European */
{ "bst", tDAYZONE, HOUR( 0) }, /* British Summer */
{ "wat", tZONE, HOUR( 1) }, /* West Africa */
{ "at", tZONE, HOUR( 2) }, /* Azores */
#if 0
/* For completeness. BST is also British Summer, and GST is
* also Guam Standard. */
{ "bst", tZONE, HOUR( 3) }, /* Brazil Standard */
{ "gst", tZONE, HOUR( 3) }, /* Greenland Standard */
#endif
#if 0
{ "nft", tZONE, HOUR(3.5) }, /* Newfoundland */
{ "nst", tZONE, HOUR(3.5) }, /* Newfoundland Standard */
{ "ndt", tDAYZONE, HOUR(3.5) }, /* Newfoundland Daylight */
#endif
{ "ast", tZONE, HOUR( 4) }, /* Atlantic Standard */
{ "adt", tDAYZONE, HOUR( 4) }, /* Atlantic Daylight */
{ "est", tZONE, HOUR( 5) }, /* Eastern Standard */
{ "edt", tDAYZONE, HOUR( 5) }, /* Eastern Daylight */
{ "cst", tZONE, HOUR( 6) }, /* Central Standard */
{ "cdt", tDAYZONE, HOUR( 6) }, /* Central Daylight */
{ "mst", tZONE, HOUR( 7) }, /* Mountain Standard */
{ "mdt", tDAYZONE, HOUR( 7) }, /* Mountain Daylight */
{ "pst", tZONE, HOUR( 8) }, /* Pacific Standard */
{ "pdt", tDAYZONE, HOUR( 8) }, /* Pacific Daylight */
{ "yst", tZONE, HOUR( 9) }, /* Yukon Standard */
{ "ydt", tDAYZONE, HOUR( 9) }, /* Yukon Daylight */
{ "hst", tZONE, HOUR(10) }, /* Hawaii Standard */
{ "hdt", tDAYZONE, HOUR(10) }, /* Hawaii Daylight */
{ "cat", tZONE, HOUR(10) }, /* Central Alaska */
{ "ahst", tZONE, HOUR(10) }, /* Alaska-Hawaii Standard */
{ "nt", tZONE, HOUR(11) }, /* Nome */
{ "idlw", tZONE, HOUR(12) }, /* International Date Line West */
{ "cet", tZONE, -HOUR(1) }, /* Central European */
{ "met", tZONE, -HOUR(1) }, /* Middle European */
{ "mewt", tZONE, -HOUR(1) }, /* Middle European Winter */
{ "mest", tDAYZONE, -HOUR(1) }, /* Middle European Summer */
{ "swt", tZONE, -HOUR(1) }, /* Swedish Winter */
{ "sst", tDAYZONE, -HOUR(1) }, /* Swedish Summer */
{ "fwt", tZONE, -HOUR(1) }, /* French Winter */
{ "fst", tDAYZONE, -HOUR(1) }, /* French Summer */
{ "eet", tZONE, -HOUR(2) }, /* Eastern Europe, USSR Zone 1 */
{ "bt", tZONE, -HOUR(3) }, /* Baghdad, USSR Zone 2 */
#if 0
{ "it", tZONE, -HOUR(3.5) },/* Iran */
#endif
{ "zp4", tZONE, -HOUR(4) }, /* USSR Zone 3 */
{ "zp5", tZONE, -HOUR(5) }, /* USSR Zone 4 */
#if 0
{ "ist", tZONE, -HOUR(5.5) },/* Indian Standard */
#endif
{ "zp6", tZONE, -HOUR(6) }, /* USSR Zone 5 */
#if 0
/* For completeness. NST is also Newfoundland Stanard, and SST is
* also Swedish Summer. */
{ "nst", tZONE, -HOUR(6.5) },/* North Sumatra */
{ "sst", tZONE, -HOUR(7) }, /* South Sumatra, USSR Zone 6 */
#endif /* 0 */
{ "wast", tZONE, -HOUR(7) }, /* West Australian Standard */
{ "wadt", tDAYZONE, -HOUR(7) }, /* West Australian Daylight */
#if 0
{ "jt", tZONE, -HOUR(7.5) },/* Java (3pm in Cronusland!) */
#endif
{ "cct", tZONE, -HOUR(8) }, /* China Coast, USSR Zone 7 */
{ "jst", tZONE, -HOUR(9) }, /* Japan Standard, USSR Zone 8 */
#if 0
{ "cast", tZONE, -HOUR(9.5) },/* Central Australian Standard */
{ "cadt", tDAYZONE, -HOUR(9.5) },/* Central Australian Daylight */
#endif
{ "east", tZONE, -HOUR(10) }, /* Eastern Australian Standard */
{ "eadt", tDAYZONE, -HOUR(10) }, /* Eastern Australian Daylight */
{ "gst", tZONE, -HOUR(10) }, /* Guam Standard, USSR Zone 9 */
{ "nzt", tZONE, -HOUR(12) }, /* New Zealand */
{ "nzst", tZONE, -HOUR(12) }, /* New Zealand Standard */
{ "nzdt", tDAYZONE, -HOUR(12) }, /* New Zealand Daylight */
{ "idle", tZONE, -HOUR(12) }, /* International Date Line East */
{ NULL, 0, 0 }
};
/* Military timezone table. */
static TABLE const MilitaryTable[] = {
{ "a", tZONE, HOUR( 1) },
{ "b", tZONE, HOUR( 2) },
{ "c", tZONE, HOUR( 3) },
{ "d", tZONE, HOUR( 4) },
{ "e", tZONE, HOUR( 5) },
{ "f", tZONE, HOUR( 6) },
{ "g", tZONE, HOUR( 7) },
{ "h", tZONE, HOUR( 8) },
{ "i", tZONE, HOUR( 9) },
{ "k", tZONE, HOUR( 10) },
{ "l", tZONE, HOUR( 11) },
{ "m", tZONE, HOUR( 12) },
{ "n", tZONE, HOUR(- 1) },
{ "o", tZONE, HOUR(- 2) },
{ "p", tZONE, HOUR(- 3) },
{ "q", tZONE, HOUR(- 4) },
{ "r", tZONE, HOUR(- 5) },
{ "s", tZONE, HOUR(- 6) },
{ "t", tZONE, HOUR(- 7) },
{ "u", tZONE, HOUR(- 8) },
{ "v", tZONE, HOUR(- 9) },
{ "w", tZONE, HOUR(-10) },
{ "x", tZONE, HOUR(-11) },
{ "y", tZONE, HOUR(-12) },
{ "z", tZONE, HOUR( 0) },
{ NULL, 0, 0 }
};
/* ARGSUSED */
static int
yyerror(const char *s __unused)
{
return 0;
}
static time_t
ToSeconds(time_t Hours, time_t Minutes, time_t Seconds, MERIDIAN Meridian)
{
if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 59)
return -1;
switch (Meridian) {
case MER24:
if (Hours < 0 || Hours > 23)
return -1;
return (Hours * 60L + Minutes) * 60L + Seconds;
case MERam:
if (Hours < 1 || Hours > 12)
return -1;
if (Hours == 12)
Hours = 0;
return (Hours * 60L + Minutes) * 60L + Seconds;
case MERpm:
if (Hours < 1 || Hours > 12)
return -1;
if (Hours == 12)
Hours = 0;
return ((Hours + 12) * 60L + Minutes) * 60L + Seconds;
default:
abort ();
}
/* NOTREACHED */
}
/* Year is either
* A negative number, which means to use its absolute value (why?)
* A number from 0 to 99, which means a year from 1900 to 1999, or
* The actual year (>=100). */
static time_t
Convert(time_t Month, time_t Day, time_t Year,
time_t Hours, time_t Minutes, time_t Seconds,
MERIDIAN Meridian, DSTMODE DSTmode)
{
static int DaysInMonth[12] = {
31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};
time_t tod;
time_t Julian;
int i;
struct tm *ltm;
if (Year < 0)
Year = -Year;
if (Year < 69)
Year += 2000;
else if (Year < 100)
Year += 1900;
DaysInMonth[1] = Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0)
? 29 : 28;
/* Checking for 2038 bogusly assumes that time_t is 32 bits. But
I'm too lazy to try to check for time_t overflow in another way. */
if (Year < EPOCH || Year > 2038
|| Month < 1 || Month > 12
/* Lint fluff: "conversion from long may lose accuracy" */
|| Day < 1 || Day > DaysInMonth[(int)--Month])
/* FIXME:
* It would be nice to set a global error string here.
* "February 30 is not a valid date" is much more informative than
* "Can't parse date/time: 100 months" when the user input was
* "100 months" and addition resolved that to February 30, for
* example. See rcs2-7 in src/sanity.sh for more. */
return -1;
for (Julian = Day - 1, i = 0; i < Month; i++)
Julian += DaysInMonth[i];
for (i = EPOCH; i < Year; i++)
Julian += 365 + (i % 4 == 0);
Julian *= SECSPERDAY;
Julian += yyTimezone * 60L;
if ((tod = ToSeconds(Hours, Minutes, Seconds, Meridian)) < 0)
return -1;
Julian += tod;
ltm = localtime(&Julian);
fprintf(stderr, "DST %d TZ %s %d\n", DSTmode, ltm->tm_zone, ltm->tm_isdst);
if (DSTmode == DSTon
|| (DSTmode == DSTmaybe && localtime(&Julian)->tm_isdst))
Julian -= 60 * 60;
return Julian;
}
static time_t
DSTcorrect(time_t Start, time_t Future)
{
time_t StartDay;
time_t FutureDay;
StartDay = (localtime(&Start)->tm_hour + 1) % 24;
FutureDay = (localtime(&Future)->tm_hour + 1) % 24;
return (Future - Start) + (StartDay - FutureDay) * 60L * 60L;
}
static time_t
RelativeDate(time_t Start, time_t DayOrdinal, time_t DayNumber)
{
struct tm *tm;
time_t now;
now = Start;
tm = localtime(&now);
now += SECSPERDAY * ((DayNumber - tm->tm_wday + 7) % 7);
now += 7 * SECSPERDAY * (DayOrdinal <= 0 ? DayOrdinal : DayOrdinal - 1);
return DSTcorrect(Start, now);
}
static time_t
RelativeMonth(time_t Start, time_t RelMonth)
{
struct tm *tm;
time_t Month;
time_t Year;
if (RelMonth == 0)
return 0;
tm = localtime(&Start);
Month = 12 * (tm->tm_year + 1900) + tm->tm_mon + RelMonth;
Year = Month / 12;
Month = Month % 12 + 1;
return DSTcorrect(Start,
Convert(Month, (time_t)tm->tm_mday, Year,
(time_t)tm->tm_hour, (time_t)tm->tm_min, (time_t)tm->tm_sec,
MER24, DSTmaybe));
}
static int
LookupWord(char *buff)
{
char *p;
char *q;
const TABLE *tp;
int i;
int abbrev;
/* Make it lowercase. */
for (p = buff; *p; p++)
if (isupper(*p))
*p = tolower(*p);
if (strcmp(buff, "am") == 0 || strcmp(buff, "a.m.") == 0) {
yylval.Meridian = MERam;
return tMERIDIAN;
}
if (strcmp(buff, "pm") == 0 || strcmp(buff, "p.m.") == 0) {
yylval.Meridian = MERpm;
return tMERIDIAN;
}
/* See if we have an abbreviation for a month. */
if (strlen(buff) == 3)
abbrev = 1;
else if (strlen(buff) == 4 && buff[3] == '.') {
abbrev = 1;
buff[3] = '\0';
}
else
abbrev = 0;
for (tp = MonthDayTable; tp->name; tp++) {
if (abbrev) {
if (strncmp(buff, tp->name, 3) == 0) {
yylval.Number = tp->value;
return tp->type;
}
}
else if (strcmp(buff, tp->name) == 0) {
yylval.Number = tp->value;
return tp->type;
}
}
for (tp = TimezoneTable; tp->name; tp++)
if (strcmp(buff, tp->name) == 0) {
yylval.Number = tp->value;
return tp->type;
}
if (strcmp(buff, "dst") == 0)
return tDST;
for (tp = UnitsTable; tp->name; tp++)
if (strcmp(buff, tp->name) == 0) {
yylval.Number = tp->value;
return tp->type;
}
/* Strip off any plural and try the units table again. */
i = strlen(buff) - 1;
if (buff[i] == 's') {
buff[i] = '\0';
for (tp = UnitsTable; tp->name; tp++)
if (strcmp(buff, tp->name) == 0) {
yylval.Number = tp->value;
return tp->type;
}
buff[i] = 's'; /* Put back for "this" in OtherTable. */
}
for (tp = OtherTable; tp->name; tp++)
if (strcmp(buff, tp->name) == 0) {
yylval.Number = tp->value;
return tp->type;
}
/* Military timezones. */
if (buff[1] == '\0' && isalpha(*buff)) {
for (tp = MilitaryTable; tp->name; tp++)
if (strcmp(buff, tp->name) == 0) {
yylval.Number = tp->value;
return tp->type;
}
}
/* Drop out any periods and try the timezone table again. */
for (i = 0, p = q = buff; *q; q++)
if (*q != '.')
*p++ = *q;
else
i++;
*p = '\0';
if (i)
for (tp = TimezoneTable; tp->name; tp++)
if (strcmp(buff, tp->name) == 0) {
yylval.Number = tp->value;
return tp->type;
}
return tID;
}
static int
yylex()
{
char c;
char *p;
char buff[20];
int Count;
int sign;
for ( ; ; ) {
while (isspace(*yyInput))
yyInput++;
if (isdigit(c = *yyInput) || c == '-' || c == '+') {
if (c == '-' || c == '+') {
sign = c == '-' ? -1 : 1;
if (!isdigit(*++yyInput))
/* skip the '-' sign */
continue;
}
else
sign = 0;
for (yylval.Number = 0; isdigit(c = *yyInput++); )
yylval.Number = 10 * yylval.Number + c - '0';
yyInput--;
if (sign < 0)
yylval.Number = -yylval.Number;
return sign ? tSNUMBER : tUNUMBER;
}
if (isalpha(c)) {
for (p = buff; isalpha(c = *yyInput++) || c == '.'; )
if (p < &buff[sizeof buff - 1])
*p++ = c;
*p = '\0';
yyInput--;
return LookupWord(buff);
}
if (c != '(')
return *yyInput++;
Count = 0;
do {
c = *yyInput++;
if (c == '\0')
return c;
if (c == '(')
Count++;
else if (c == ')')
Count--;
} while (Count > 0);
}
}
#define TM_YEAR_ORIGIN 1900
time_t
get_date(char *p)
{
struct tm *tm, gmt;
time_t Start;
time_t tod;
time_t nowtime;
struct tm *gmt_ptr;
yyInput = p;
(void)time (&nowtime);
gmt_ptr = gmtime (&nowtime);
if (gmt_ptr != NULL)
{
/* Make a copy, in case localtime modifies *tm (I think
that comment now applies to *gmt_ptr, but I am too
lazy to dig into how gmtime and locatime allocate the
structures they return pointers to). */
gmt = *gmt_ptr;
}
if (! (tm = localtime (&nowtime)))
return -1;
tm = localtime(&nowtime);
yyYear = tm->tm_year + 1900;
yyMonth = tm->tm_mon + 1;
yyDay = tm->tm_mday;
yyTimezone = tm->tm_gmtoff;
yyDSTmode = DSTmaybe;
yyHour = 0;
yyMinutes = 0;
yySeconds = 0;
yyMeridian = MER24;
yyRelSeconds = 0;
yyRelMonth = 0;
yyHaveDate = 0;
yyHaveDay = 0;
yyHaveRel = 0;
yyHaveTime = 0;
yyHaveZone = 0;
if (yyparse()
|| yyHaveTime > 1 || yyHaveZone > 1 || yyHaveDate > 1 || yyHaveDay > 1)
return -1;
if (yyHaveDate || yyHaveTime || yyHaveDay) {
Start = Convert(yyMonth, yyDay, yyYear, yyHour, yyMinutes, yySeconds,
yyMeridian, yyDSTmode);
if (Start < 0)
return -1;
}
else {
Start = nowtime;
if (!yyHaveRel)
Start -= ((tm->tm_hour * 60L + tm->tm_min) * 60L) + tm->tm_sec;
}
Start += yyRelSeconds;
Start += RelativeMonth(Start, yyRelMonth);
if (yyHaveDay && !yyHaveDate) {
tod = RelativeDate(Start, yyDayOrdinal, yyDayNumber);
Start += tod;
}
/* Have to do *something* with a legitimate -1 so it's distinguishable
* from the error return value. (Alternately could set errno on error.) */
return Start == -1 ? 0 : Start;
}

View File

@ -0,0 +1,62 @@
/*-
* Copyright (c) 2005-2008 Poul-Henning Kamp
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#include <sys/stdint.h>
/* CREATORS */
const char *fifolog_create(const char *fn, off_t size, unsigned recsize);
/* WRITERS */
struct fifolog_writer;
struct fifolog_writer *fifolog_write_new(void);
const char *fifolog_write_open(struct fifolog_writer *f, const char *fn, unsigned writerate, unsigned syncrate, int compression);
int fifolog_write_bytes(struct fifolog_writer *f, uint32_t id, time_t now, const void *ptr, unsigned len);
void fifolog_write_bytes_poll(struct fifolog_writer *f, uint32_t id, time_t now, const void *ptr, unsigned len);
int fifolog_write_poll(struct fifolog_writer *f, time_t now);
void fifolog_write_close(struct fifolog_writer *f);
void fifolog_write_destroy(struct fifolog_writer *f);
int fifolog_write_flush(struct fifolog_writer *f);
extern const char *fifolog_write_statnames[];
/* READERS */
typedef void fifolog_reader_render_t(void *priv, time_t when, unsigned flag, const unsigned char *p, unsigned l);
struct fifolog_reader;
struct fifolog_reader *fifolog_reader_open(const char *fname);
off_t fifolog_reader_seek(const struct fifolog_reader *fl, time_t t0);
void fifolog_reader_process(struct fifolog_reader *fl, off_t from, fifolog_reader_render_t *func, void *priv, time_t end);
/* UTILS */
time_t get_date(char *p);
#if (__FreeBSD__ < 7)
int expand_number(char *_buf, int64_t *_num);
#endif

View File

@ -0,0 +1,45 @@
/*-
* Copyright (c) 2005-2008
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
struct fifolog_file {
unsigned magic;
#define FIFOLOG_FILE_MAGIC 0x307ea50d
unsigned recsize;
off_t logsize;
int fd;
z_stream *zs;
unsigned char *recbuf;
};
const char *fifolog_int_open(struct fifolog_file **ff, const char *fname, int mode);
void fifolog_int_close(struct fifolog_file **ff);
int fifolog_int_read(const struct fifolog_file *ff, off_t recno);
const char *fifolog_int_findend(const struct fifolog_file *ff, off_t *last);

View File

@ -0,0 +1,66 @@
/*-
* Copyright (c) 2005-2008 Poul-Henning Kamp
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#define ALLOC_OBJ(to, type_magic) \
do { \
(to) = calloc(sizeof *(to), 1); \
assert((to) != NULL); \
(to)->magic = (type_magic); \
} while (0)
#define FREE_OBJ(to) \
do { \
(to)->magic = (0); \
free(to); \
} while (0)
#define CHECK_OBJ(ptr, type_magic) \
do { \
assert((ptr)->magic == type_magic); \
} while (0)
#define CHECK_OBJ_NOTNULL(ptr, type_magic) \
do { \
assert((ptr) != NULL); \
assert((ptr)->magic == type_magic); \
} while (0)
#define CAST_OBJ(to, from, type_magic) \
do { \
(to) = (from); \
if ((to) != NULL) \
CHECK_OBJ((to), (type_magic)); \
} while (0);
#define CAST_OBJ_NOTNULL(to, from, type_magic) \
do { \
(to) = (from); \
assert((to) != NULL); \
CHECK_OBJ((to), (type_magic)); \
} while (0);