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:
parent
801772ec32
commit
662cb04c25
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=176998
10
usr.sbin/fifolog/Makefile
Normal file
10
usr.sbin/fifolog/Makefile
Normal 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
|
13
usr.sbin/fifolog/Makefile.inc
Normal file
13
usr.sbin/fifolog/Makefile.inc
Normal 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"
|
22
usr.sbin/fifolog/fifolog_create/Makefile
Normal file
22
usr.sbin/fifolog/fifolog_create/Makefile
Normal 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
|
210
usr.sbin/fifolog/fifolog_create/fifolog.1
Normal file
210
usr.sbin/fifolog/fifolog_create/fifolog.1
Normal 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
|
105
usr.sbin/fifolog/fifolog_create/fifolog_create.c
Normal file
105
usr.sbin/fifolog/fifolog_create/fifolog_create.c
Normal 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);
|
||||
}
|
21
usr.sbin/fifolog/fifolog_reader/Makefile
Normal file
21
usr.sbin/fifolog/fifolog_reader/Makefile
Normal 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
|
170
usr.sbin/fifolog/fifolog_reader/fifolog_reader.c
Normal file
170
usr.sbin/fifolog/fifolog_reader/fifolog_reader.c
Normal 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);
|
||||
}
|
16
usr.sbin/fifolog/fifolog_writer/Makefile
Normal file
16
usr.sbin/fifolog/fifolog_writer/Makefile
Normal 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
|
105
usr.sbin/fifolog/fifolog_writer/fifolog_writer.c
Normal file
105
usr.sbin/fifolog/fifolog_writer/fifolog_writer.c
Normal 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);
|
||||
}
|
49
usr.sbin/fifolog/flint.lnt
Normal file
49
usr.sbin/fifolog/flint.lnt
Normal 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
|
17
usr.sbin/fifolog/lib/Makefile
Normal file
17
usr.sbin/fifolog/lib/Makefile
Normal 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}
|
138
usr.sbin/fifolog/lib/fifolog.h
Normal file
138
usr.sbin/fifolog/lib/fifolog.h
Normal 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_ */
|
122
usr.sbin/fifolog/lib/fifolog_create.c
Normal file
122
usr.sbin/fifolog/lib/fifolog_create.c
Normal 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);
|
||||
}
|
276
usr.sbin/fifolog/lib/fifolog_int.c
Normal file
276
usr.sbin/fifolog/lib/fifolog_int.c
Normal 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);
|
||||
}
|
315
usr.sbin/fifolog/lib/fifolog_reader.c
Normal file
315
usr.sbin/fifolog/lib/fifolog_reader.c
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
65
usr.sbin/fifolog/lib/fifolog_write.h
Normal file
65
usr.sbin/fifolog/lib/fifolog_write.h
Normal 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;
|
||||
};
|
416
usr.sbin/fifolog/lib/fifolog_write_poll.c
Normal file
416
usr.sbin/fifolog/lib/fifolog_write_poll.c
Normal 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);
|
||||
}
|
889
usr.sbin/fifolog/lib/getdate.y
Normal file
889
usr.sbin/fifolog/lib/getdate.y
Normal 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;
|
||||
}
|
62
usr.sbin/fifolog/lib/libfifolog.h
Normal file
62
usr.sbin/fifolog/lib/libfifolog.h
Normal 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
|
||||
|
45
usr.sbin/fifolog/lib/libfifolog_int.h
Normal file
45
usr.sbin/fifolog/lib/libfifolog_int.h
Normal 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);
|
66
usr.sbin/fifolog/lib/miniobj.h
Normal file
66
usr.sbin/fifolog/lib/miniobj.h
Normal 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);
|
||||
|
Loading…
Reference in New Issue
Block a user