summaryrefslogtreecommitdiffstats
path: root/usr.sbin/fifolog
diff options
context:
space:
mode:
authorphk <phk@FreeBSD.org>2008-03-09 19:14:36 +0000
committerphk <phk@FreeBSD.org>2008-03-09 19:14:36 +0000
commit329dcba2dfdf5d9e4878196bdfc8e7a951d13d22 (patch)
tree1ac353f6fcd504cada7e247a46746cb3f8bb97eb /usr.sbin/fifolog
parent7c7baa655e11f923a155a5367e5ec723ed0c117a (diff)
downloadFreeBSD-src-329dcba2dfdf5d9e4878196bdfc8e7a951d13d22.zip
FreeBSD-src-329dcba2dfdf5d9e4878196bdfc8e7a951d13d22.tar.gz
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.
Diffstat (limited to 'usr.sbin/fifolog')
-rw-r--r--usr.sbin/fifolog/Makefile10
-rw-r--r--usr.sbin/fifolog/Makefile.inc13
-rw-r--r--usr.sbin/fifolog/fifolog_create/Makefile22
-rw-r--r--usr.sbin/fifolog/fifolog_create/fifolog.1210
-rw-r--r--usr.sbin/fifolog/fifolog_create/fifolog_create.c105
-rw-r--r--usr.sbin/fifolog/fifolog_reader/Makefile21
-rw-r--r--usr.sbin/fifolog/fifolog_reader/fifolog_reader.c170
-rw-r--r--usr.sbin/fifolog/fifolog_writer/Makefile16
-rw-r--r--usr.sbin/fifolog/fifolog_writer/fifolog_writer.c105
-rw-r--r--usr.sbin/fifolog/flint.lnt49
-rw-r--r--usr.sbin/fifolog/lib/Makefile17
-rw-r--r--usr.sbin/fifolog/lib/fifolog.h138
-rw-r--r--usr.sbin/fifolog/lib/fifolog_create.c122
-rw-r--r--usr.sbin/fifolog/lib/fifolog_int.c276
-rw-r--r--usr.sbin/fifolog/lib/fifolog_reader.c315
-rw-r--r--usr.sbin/fifolog/lib/fifolog_write.h65
-rw-r--r--usr.sbin/fifolog/lib/fifolog_write_poll.c416
-rw-r--r--usr.sbin/fifolog/lib/getdate.y889
-rw-r--r--usr.sbin/fifolog/lib/libfifolog.h62
-rw-r--r--usr.sbin/fifolog/lib/libfifolog_int.h45
-rw-r--r--usr.sbin/fifolog/lib/miniobj.h66
21 files changed, 3132 insertions, 0 deletions
diff --git a/usr.sbin/fifolog/Makefile b/usr.sbin/fifolog/Makefile
new file mode 100644
index 0000000..596410c
--- /dev/null
+++ b/usr.sbin/fifolog/Makefile
@@ -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
diff --git a/usr.sbin/fifolog/Makefile.inc b/usr.sbin/fifolog/Makefile.inc
new file mode 100644
index 0000000..f62f589
--- /dev/null
+++ b/usr.sbin/fifolog/Makefile.inc
@@ -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"
diff --git a/usr.sbin/fifolog/fifolog_create/Makefile b/usr.sbin/fifolog/fifolog_create/Makefile
new file mode 100644
index 0000000..0c4bd65
--- /dev/null
+++ b/usr.sbin/fifolog/fifolog_create/Makefile
@@ -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
diff --git a/usr.sbin/fifolog/fifolog_create/fifolog.1 b/usr.sbin/fifolog/fifolog_create/fifolog.1
new file mode 100644
index 0000000..91d1877
--- /dev/null
+++ b/usr.sbin/fifolog/fifolog_create/fifolog.1
@@ -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
diff --git a/usr.sbin/fifolog/fifolog_create/fifolog_create.c b/usr.sbin/fifolog/fifolog_create/fifolog_create.c
new file mode 100644
index 0000000..2b93765
--- /dev/null
+++ b/usr.sbin/fifolog/fifolog_create/fifolog_create.c
@@ -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);
+}
diff --git a/usr.sbin/fifolog/fifolog_reader/Makefile b/usr.sbin/fifolog/fifolog_reader/Makefile
new file mode 100644
index 0000000..99294da
--- /dev/null
+++ b/usr.sbin/fifolog/fifolog_reader/Makefile
@@ -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
diff --git a/usr.sbin/fifolog/fifolog_reader/fifolog_reader.c b/usr.sbin/fifolog/fifolog_reader/fifolog_reader.c
new file mode 100644
index 0000000..6c4dc41
--- /dev/null
+++ b/usr.sbin/fifolog/fifolog_reader/fifolog_reader.c
@@ -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);
+}
diff --git a/usr.sbin/fifolog/fifolog_writer/Makefile b/usr.sbin/fifolog/fifolog_writer/Makefile
new file mode 100644
index 0000000..7613085
--- /dev/null
+++ b/usr.sbin/fifolog/fifolog_writer/Makefile
@@ -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
diff --git a/usr.sbin/fifolog/fifolog_writer/fifolog_writer.c b/usr.sbin/fifolog/fifolog_writer/fifolog_writer.c
new file mode 100644
index 0000000..469d284
--- /dev/null
+++ b/usr.sbin/fifolog/fifolog_writer/fifolog_writer.c
@@ -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);
+}
diff --git a/usr.sbin/fifolog/flint.lnt b/usr.sbin/fifolog/flint.lnt
new file mode 100644
index 0000000..16ee7ad
--- /dev/null
+++ b/usr.sbin/fifolog/flint.lnt
@@ -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
diff --git a/usr.sbin/fifolog/lib/Makefile b/usr.sbin/fifolog/lib/Makefile
new file mode 100644
index 0000000..fedfc50
--- /dev/null
+++ b/usr.sbin/fifolog/lib/Makefile
@@ -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}
diff --git a/usr.sbin/fifolog/lib/fifolog.h b/usr.sbin/fifolog/lib/fifolog.h
new file mode 100644
index 0000000..d5c8297
--- /dev/null
+++ b/usr.sbin/fifolog/lib/fifolog.h
@@ -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_ */
diff --git a/usr.sbin/fifolog/lib/fifolog_create.c b/usr.sbin/fifolog/lib/fifolog_create.c
new file mode 100644
index 0000000..68f8cef
--- /dev/null
+++ b/usr.sbin/fifolog/lib/fifolog_create.c
@@ -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);
+}
diff --git a/usr.sbin/fifolog/lib/fifolog_int.c b/usr.sbin/fifolog/lib/fifolog_int.c
new file mode 100644
index 0000000..9093174
--- /dev/null
+++ b/usr.sbin/fifolog/lib/fifolog_int.c
@@ -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);
+}
diff --git a/usr.sbin/fifolog/lib/fifolog_reader.c b/usr.sbin/fifolog/lib/fifolog_reader.c
new file mode 100644
index 0000000..37a03b7
--- /dev/null
+++ b/usr.sbin/fifolog/lib/fifolog_reader.c
@@ -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);
+ }
+ }
+ }
+}
diff --git a/usr.sbin/fifolog/lib/fifolog_write.h b/usr.sbin/fifolog/lib/fifolog_write.h
new file mode 100644
index 0000000..06b3233
--- /dev/null
+++ b/usr.sbin/fifolog/lib/fifolog_write.h
@@ -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;
+};
diff --git a/usr.sbin/fifolog/lib/fifolog_write_poll.c b/usr.sbin/fifolog/lib/fifolog_write_poll.c
new file mode 100644
index 0000000..86615aa
--- /dev/null
+++ b/usr.sbin/fifolog/lib/fifolog_write_poll.c
@@ -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);
+}
diff --git a/usr.sbin/fifolog/lib/getdate.y b/usr.sbin/fifolog/lib/getdate.y
new file mode 100644
index 0000000..93b5b6b
--- /dev/null
+++ b/usr.sbin/fifolog/lib/getdate.y
@@ -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;
+}
diff --git a/usr.sbin/fifolog/lib/libfifolog.h b/usr.sbin/fifolog/lib/libfifolog.h
new file mode 100644
index 0000000..430e72b
--- /dev/null
+++ b/usr.sbin/fifolog/lib/libfifolog.h
@@ -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
+
diff --git a/usr.sbin/fifolog/lib/libfifolog_int.h b/usr.sbin/fifolog/lib/libfifolog_int.h
new file mode 100644
index 0000000..54ab897
--- /dev/null
+++ b/usr.sbin/fifolog/lib/libfifolog_int.h
@@ -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);
diff --git a/usr.sbin/fifolog/lib/miniobj.h b/usr.sbin/fifolog/lib/miniobj.h
new file mode 100644
index 0000000..38a907e
--- /dev/null
+++ b/usr.sbin/fifolog/lib/miniobj.h
@@ -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);
+
OpenPOWER on IntegriCloud