diff options
Diffstat (limited to 'usr.sbin/fifolog/lib')
| -rw-r--r-- | usr.sbin/fifolog/lib/Makefile | 12 | ||||
| -rw-r--r-- | usr.sbin/fifolog/lib/Makefile.depend | 14 | ||||
| -rw-r--r-- | usr.sbin/fifolog/lib/fifolog.h | 138 | ||||
| -rw-r--r-- | usr.sbin/fifolog/lib/fifolog_create.c | 124 | ||||
| -rw-r--r-- | usr.sbin/fifolog/lib/fifolog_int.c | 256 | ||||
| -rw-r--r-- | usr.sbin/fifolog/lib/fifolog_reader.c | 322 | ||||
| -rw-r--r-- | usr.sbin/fifolog/lib/fifolog_write.h | 75 | ||||
| -rw-r--r-- | usr.sbin/fifolog/lib/fifolog_write_poll.c | 420 | ||||
| -rw-r--r-- | usr.sbin/fifolog/lib/getdate.y | 876 | ||||
| -rw-r--r-- | usr.sbin/fifolog/lib/libfifolog.h | 47 | ||||
| -rw-r--r-- | usr.sbin/fifolog/lib/libfifolog_int.h | 45 | ||||
| -rw-r--r-- | usr.sbin/fifolog/lib/miniobj.h | 74 | 
12 files changed, 2403 insertions, 0 deletions
| diff --git a/usr.sbin/fifolog/lib/Makefile b/usr.sbin/fifolog/lib/Makefile new file mode 100644 index 000000000000..e4aa62fb680f --- /dev/null +++ b/usr.sbin/fifolog/lib/Makefile @@ -0,0 +1,12 @@ +LIB=	fifolog +INTERNALLIB=	# API not published or supported. + +SRCS=	fifolog_int.c fifolog_create.c fifolog_write_poll.c fifolog_reader.c +SRCS+=	getdate.y + +CFLAGS+= -I${.CURDIR} +LIBADD=	z + +NO_WMISSING_VARIABLE_DECLARATIONS= + +.include <bsd.lib.mk> diff --git a/usr.sbin/fifolog/lib/Makefile.depend b/usr.sbin/fifolog/lib/Makefile.depend new file mode 100644 index 000000000000..37782773d8ea --- /dev/null +++ b/usr.sbin/fifolog/lib/Makefile.depend @@ -0,0 +1,14 @@ +# Autogenerated - do NOT edit! + +DIRDEPS = \ +	include \ +	include/xlocale \ +	lib/libz \ +	usr.bin/yacc.host \ + + +.include <dirdeps.mk> + +.if ${DEP_RELDIR} == ${_DEP_RELDIR} +# local dependencies - needed for -jN in clean tree +.endif diff --git a/usr.sbin/fifolog/lib/fifolog.h b/usr.sbin/fifolog/lib/fifolog.h new file mode 100644 index 000000000000..9a673db89f06 --- /dev/null +++ b/usr.sbin/fifolog/lib/fifolog.h @@ -0,0 +1,138 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * 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. + */ + +#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 outer 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 outer layer + * record boundaries, from where reading can be initiated. + * + * + * The outer 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 presence 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 outer layer (apart from a natural correlation with padding) since + * zlibs data stream handles this without help. + * + * + * The inner layer: + * ---------------- + * The inner layer contains data identification and to the second + * timestamping (the timestamp in the outer layer 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 length encoded binary sequence: + * + * If (ident & FIFOLOG_LENGTH) the record is prefixed by: + *	{0|4}	8	length of binary data + * + */ + +/* Magic identification string */ +#define FIFOLOG_FMT_MAGIC	"Measured FIFOLOG Ver 1.01\n" + +/* Offset of the 32be encoded recordsize in the first sector */ +#define FIFOLOG_OFF_BS		0x20 + +#define FIFOLOG_FLG_1BYTE	0x01 +#define FIFOLOG_FLG_4BYTE	0x02 +#define FIFOLOG_FLG_RESTART	0x40 +#define FIFOLOG_FLG_SYNC	0x80 + +#define FIFOLOG_TIMESTAMP	0x80000000 +#define FIFOLOG_LENGTH		0x40000000 +#define FIFOLOG_IDENT		0x3fffffff + +#endif /* __LOCAL_FIFOLOG_H_ */ diff --git a/usr.sbin/fifolog/lib/fifolog_create.c b/usr.sbin/fifolog/lib/fifolog_create.c new file mode 100644 index 000000000000..5737cba15db6 --- /dev/null +++ b/usr.sbin/fifolog/lib/fifolog_create.c @@ -0,0 +1,124 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * 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. + */ + +#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, ssize_t recsize) +{ +	int i, fd; +	ssize_t u; +	u_int uu; +	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, &uu); +	u = uu; +	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(1, recsize); +	if (buf == NULL) +		return ("Could not malloc"); + +	strcpy(buf, FIFOLOG_FMT_MAGIC);		/*lint !e64 */ +	be32enc(buf + FIFOLOG_OFF_BS, recsize); +	if (recsize != pwrite(fd, buf, recsize, 0)) { +		i = errno; +		free(buf); +		errno = i; +		return ("Could not write first sector"); +	} +	memset(buf, 0, recsize); +	if ((int)recsize != pwrite(fd, buf, recsize, recsize)) { +		i = errno; +		free(buf); +		errno = i; +		return ("Could not write second sector"); +	} +	free(buf); +	assert(0 == close(fd)); +	return (NULL); +} diff --git a/usr.sbin/fifolog/lib/fifolog_int.c b/usr.sbin/fifolog/lib/fifolog_int.c new file mode 100644 index 000000000000..2cbc430993be --- /dev/null +++ b/usr.sbin/fifolog/lib/fifolog_int.c @@ -0,0 +1,256 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * 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. + */ + +#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" + +/* + * 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; +	ssize_t 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); +		assert(i == 0); +		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(1, sizeof(*f->zs)); +	if (f->zs == NULL) +		return ("cannot malloc"); + +	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); +} + +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 (-2); +	if (i != (int)ff->recsize) +		return (-3); +	return (0); +} + +/* + * Find the last written record in the fifolog. + * + * Return is error string or NULL on success + */ + +const char * +fifolog_int_findend(const struct fifolog_file *ff, off_t *last) +{ +	off_t o, s; +	int e; +	unsigned seq0, seq; + +	fifolog_int_file_assert(ff); + +	o = 0; +	e = fifolog_int_read(ff, o); +	if (e) +		return("Read error, first record"); + +	seq0 = be32dec(ff->recbuf); + +	/* If the first records sequence is zero, the fifolog is empty */ +	if (seq0 == 0) { +		*last = o; +		return (NULL); +	} + +	/* Do a binary search for a discontinuity in the sequence numbers */ +	s = ff->logsize / 2; +	do { +		e = fifolog_int_read(ff, o + s); +		if (e) +			return ("Read error while searching"); +		seq = be32dec(ff->recbuf); +		if (seq == seq0 + s) { +			o += s; +			seq0 = seq; +		} +		s /= 2; +		assert(o < ff->logsize); +	} while (s > 0); + +	*last = o; +	return (NULL); +} diff --git a/usr.sbin/fifolog/lib/fifolog_reader.c b/usr.sbin/fifolog/lib/fifolog_reader.c new file mode 100644 index 000000000000..092d630d5b3f --- /dev/null +++ b/usr.sbin/fifolog/lib/fifolog_reader.c @@ -0,0 +1,322 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * 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. + */ + +#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(1, sizeof(*fr)); +	if (fr == NULL) +		err(1, "Cannot malloc"); + +	retval = fifolog_int_open(&fr->ff, fname, 0); +	if (retval != NULL) +		err(1, "%s", retval); + +	fr->obuf = calloc(16, fr->ff->recsize); +	if (fr->obuf == NULL) +		err(1, "Cannot malloc"); +	fr->olen = fr->ff->recsize * 16; + +	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 (%d) while looking for SYNC", e); +	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 (%d) while looking for SYNC", e); +		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); +		s++; +		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) { +			s = st = s / 2; +			continue; +		} +		/* 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++; +			if (p + w + v >= q) +				return (p); +		} 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 (%d)", e); +		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); +				exit (250); +			} +			assert(i == Z_OK); +			if (zs->avail_out != fr->olen) { +				q = fr->obuf + (fr->olen - zs->avail_out); +				p = fifolog_reader_chop(fr, func, priv); +				if (p < q) +					(void)memmove(fr->obuf, p, q - p); +				zs->avail_out = fr->olen - (q - p); +				zs->next_out = fr->obuf + (q - p); +			} +		} +	} +} diff --git a/usr.sbin/fifolog/lib/fifolog_write.h b/usr.sbin/fifolog/lib/fifolog_write.h new file mode 100644 index 000000000000..36186be45a15 --- /dev/null +++ b/usr.sbin/fifolog/lib/fifolog_write.h @@ -0,0 +1,75 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * 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. + */ + +#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; + +	int				cleanup; + +	intmax_t			cnt[FIFOLOG_NPOINT]; + +	uint32_t			seq; +	off_t				recno; +	uint8_t				flag; +	time_t				last; + +	ssize_t				obufsize; +	u_char				*obuf; + +	ssize_t				ibufsize; +	ssize_t				ibufptr; +	u_char				*ibuf; + +	time_t				starttime; +	time_t				lastwrite; +	time_t				lastsync; +}; + +struct fifolog_writer *fifolog_write_new(void); +const char *fifolog_write_open(struct fifolog_writer *f, const char *fn, unsigned writerate, unsigned syncrate, unsigned compression); +int fifolog_write_record(struct fifolog_writer *f, uint32_t id, time_t now, const void *ptr, ssize_t len); +int fifolog_write_poll(struct fifolog_writer *f, time_t now); +int fifolog_write_record_poll(struct fifolog_writer *f, uint32_t id, time_t now, const void *ptr, ssize_t len); +void fifolog_write_close(struct fifolog_writer *f); +void fifolog_write_destroy(struct fifolog_writer *f); +extern const char *fifolog_write_statnames[]; diff --git a/usr.sbin/fifolog/lib/fifolog_write_poll.c b/usr.sbin/fifolog/lib/fifolog_write_poll.c new file mode 100644 index 000000000000..f64a21e2b619 --- /dev/null +++ b/usr.sbin/fifolog/lib/fifolog_write_poll.c @@ -0,0 +1,420 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * 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. + */ + +#include <assert.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <stdint.h> +#include <time.h> +#include <sys/endian.h> + +#include <zlib.h> + +#include "fifolog.h" +#include "libfifolog_int.h" +#include "fifolog_write.h" +#include "miniobj.h" + +static int fifolog_write_gzip(struct fifolog_writer *f, time_t now); + +#define ALLOC(ptr, size) do {                   \ +	(*(ptr)) = calloc(1, size);             \ +	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->ff->zs->next_out + f->ff->zs->avail_out == \ +	    f->obuf + f->obufsize); +} + +/********************************************************************** + * Allocate/Destroy a new fifolog writer instance + */ + +struct fifolog_writer * +fifolog_write_new(void) +{ +	struct fifolog_writer *f; + +	ALLOC_OBJ(f, FIFOLOG_WRITER_MAGIC); +	assert(f != NULL); +	return (f); +} + +void +fifolog_write_destroy(struct fifolog_writer *f) +{ + +	free(f->obuf); +	free(f->ibuf); +	FREE_OBJ(f); +} + +/********************************************************************** + * Open/Close the fifolog + */ + +void +fifolog_write_close(struct fifolog_writer *f) +{ +	time_t now; + +	CHECK_OBJ_NOTNULL(f, FIFOLOG_WRITER_MAGIC); +	fifolog_write_assert(f); + +	f->cleanup = 1; +	time(&now); +	fifolog_write_gzip(f, now); +	fifolog_write_assert(f); +	fifolog_int_close(&f->ff); +	free(f->ff); +} + +const char * +fifolog_write_open(struct fifolog_writer *f, const char *fn, +    unsigned writerate, unsigned syncrate, unsigned 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_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); +	i = fifolog_int_read(f->ff, o); +	if (i) +		return ("Read error, looking for seq"); +	f->seq = be32dec(f->ff->recbuf); +	if (f->seq == 0) { +		/* Empty fifolog */ +		f->seq = random(); +	} else { +		f->recno = o + 1; +		f->seq++; +	} + +	f->obufsize = f->ff->recsize; +	ALLOC(&f->obuf, f->obufsize); + +	f->ibufsize = f->obufsize * 10; +	ALLOC(&f->ibuf, f->ibufsize); +	f->ibufptr = 0; + +	i = deflateInit(f->ff->zs, (int)f->compression); +	assert(i == Z_OK); + +	f->flag |= FIFOLOG_FLG_RESTART; +	f->flag |= FIFOLOG_FLG_SYNC; +	f->ff->zs->next_out = f->obuf + 9; +	f->ff->zs->avail_out = f->obufsize - 9; + +	time(&now); +	f->starttime = now; +	f->lastsync = now; +	f->lastwrite = now; + +	fifolog_write_assert(f); +	return (NULL); +} + +/********************************************************************** + * Write an output record + * Returns -1 if there are trouble writing data + */ + +static int +fifolog_write_output(struct fifolog_writer *f, int fl, time_t now) +{ +	long h, l = f->ff->zs->next_out - f->obuf; +	ssize_t i, w; +	int retval = 0; + +	h = 4;					/* seq */ +	be32enc(f->obuf, f->seq); +	f->obuf[h] = f->flag; +	h += 1;					/* flag */ +	if (f->flag & FIFOLOG_FLG_SYNC) { +		be32enc(f->obuf + h, now); +		h += 4;				/* timestamp */ +	} + +	assert(l <= (long)f->ff->recsize);	/* NB: l includes h */ +	assert(l >= h); + +	/* We will never write an entirely empty buffer */ +	if (l == h) +		return (0); + +	if (l < (long)f->ff->recsize && fl == Z_NO_FLUSH) +		return (0); + +	w = f->ff->recsize - l; +	if (w >  255) { +		be32enc(f->obuf + f->ff->recsize - 4, w); +		f->obuf[4] |= FIFOLOG_FLG_4BYTE; +	} else if (w > 0) { +		f->obuf[f->ff->recsize - 1] = (uint8_t)w; +		f->obuf[4] |= FIFOLOG_FLG_1BYTE; +	} + +	f->cnt[FIFOLOG_PT_BYTES_POST] += l - h; + +	i = pwrite(f->ff->fd, f->obuf, f->ff->recsize, +	    (f->recno + 1) * f->ff->recsize); +	if (i != f->ff->recsize) +		retval = -1; +	else +		retval = 1; + +	f->cnt[FIFOLOG_PT_WRITES]++; +	f->cnt[FIFOLOG_PT_RUNTIME] = now - f->starttime; + +	f->lastwrite = now; +	/* +	 * We increment these even on error, so as to properly skip bad, +	 * sectors or other light trouble. +	 */ +	f->seq++; +	f->recno++; + +	/* +	 * Ensure we wrap recno once we hit the file size (in records.) +	 */ +	if (f->recno >= f->ff->logsize) +		/* recno 0 is header; skip */ +		f->recno = 1; + +	f->flag = 0; + +	memset(f->obuf, 0, f->obufsize); +	f->ff->zs->next_out = f->obuf + 5; +	f->ff->zs->avail_out = f->obufsize - 5; +	return (retval); +} + +/********************************************************************** + * Run the compression engine + * Returns -1 if there are trouble writing data + */ + +static int +fifolog_write_gzip(struct fifolog_writer *f, time_t now) +{ +	int i, fl, retval = 0; + +	assert(now != 0); +	if (f->cleanup || now >= (int)(f->lastsync + f->syncrate)) { +		f->cleanup = 0; +		fl = Z_FINISH; +		f->cnt[FIFOLOG_PT_SYNC]++; +	} else if (now >= (int)(f->lastwrite + f->writerate)) { +		fl = Z_SYNC_FLUSH; +		f->cnt[FIFOLOG_PT_FLUSH]++; +	} else if (f->ibufptr == 0) +		return (0); +	else +		fl = Z_NO_FLUSH; + +	f->ff->zs->avail_in = f->ibufptr; +	f->ff->zs->next_in = f->ibuf; + +	while (1) { +		i = deflate(f->ff->zs, fl); +		assert(i == Z_OK || i == Z_BUF_ERROR || i == Z_STREAM_END); + +		i = fifolog_write_output(f, fl, now); +		if (i == 0) +			break; +		if (i < 0) +			retval = -1; +	} +	assert(f->ff->zs->avail_in == 0); +	f->ibufptr = 0; +	if (fl == Z_FINISH) { +		f->flag |= FIFOLOG_FLG_SYNC; +		f->ff->zs->next_out = f->obuf + 9; +		f->ff->zs->avail_out = f->obufsize - 9; +		f->lastsync = now; +		assert(Z_OK == deflateReset(f->ff->zs)); +	} +	return (retval); +} + +/********************************************************************** + * Poll to see if we need to flush out a record + * Returns -1 if there are trouble writing data + */ + +int +fifolog_write_poll(struct fifolog_writer *f, time_t now) +{ + +	if (now == 0) +		time(&now); +	return (fifolog_write_gzip(f, now)); +} + +/********************************************************************** + * Attempt to write an entry into the ibuf. + * Return zero if there is no space, one otherwise + */ + +int +fifolog_write_record(struct fifolog_writer *f, uint32_t id, time_t now, +    const void *ptr, ssize_t len) +{ +	const unsigned char *p; +	uint8_t buf[9]; +	ssize_t bufl; + +	fifolog_write_assert(f); +	assert(!(id & (FIFOLOG_TIMESTAMP|FIFOLOG_LENGTH))); +	assert(ptr != NULL); + +	p = ptr; +	if (len == 0) { +		len = strlen(ptr); +		len++; +	} else { +		assert(len <= 255); +		id |= FIFOLOG_LENGTH; +	} +	assert (len > 0); + +	/* Do a timestamp, if needed */ +	if (now == 0) +		time(&now); + +	if (now != f->last) +		id |= FIFOLOG_TIMESTAMP; + +	/* Emit instance+flag */ +	be32enc(buf, id); +	bufl = 4; + +	if (id & FIFOLOG_TIMESTAMP) { +		be32enc(buf + bufl, (uint32_t)now); +		bufl += 4; +	} +	if (id & FIFOLOG_LENGTH) +		buf[bufl++] = (u_char)len; + +	if (bufl + len + f->ibufptr > f->ibufsize) +		return (0); + +	memcpy(f->ibuf + f->ibufptr, buf, bufl); +	f->ibufptr += bufl; +	memcpy(f->ibuf + f->ibufptr, p, len); +	f->ibufptr += len; +	f->cnt[FIFOLOG_PT_BYTES_PRE] += bufl + len; + +	if (id & FIFOLOG_TIMESTAMP) +		f->last = now; +	return (1); +} + +/********************************************************************** + * Write an entry, polling the gzip/writer until success. + * Long binary entries are broken into 255 byte chunks. + * Returns -1 if there are problems writing data + */ + +int +fifolog_write_record_poll(struct fifolog_writer *f, uint32_t id, time_t now, +    const void *ptr, ssize_t len) +{ +	u_int l; +	const unsigned char *p; +	int retval = 0; + +	if (now == 0) +		time(&now); +	fifolog_write_assert(f); + +	assert(!(id & (FIFOLOG_TIMESTAMP|FIFOLOG_LENGTH))); +	assert(ptr != NULL); + +	if (len == 0) { +		if (!fifolog_write_record(f, id, now, ptr, len)) { +			if (fifolog_write_gzip(f, now) < 0) +				retval = -1; +			/* The string could be too long for the ibuf, so... */ +			if (!fifolog_write_record(f, id, now, ptr, len)) +				retval = -1; +		} +	} else { +		for (p = ptr; len > 0; len -= l, p += l) { +			l = len; +			if (l > 255) +				l = 255; +			while (!fifolog_write_record(f, id, now, p, l)) +				if (fifolog_write_gzip(f, now) < 0) +					retval = -1; +		} +	} +	if (fifolog_write_gzip(f, now) < 0) +		retval = -1; +	fifolog_write_assert(f); +	return (retval); +} diff --git a/usr.sbin/fifolog/lib/getdate.y b/usr.sbin/fifolog/lib/getdate.y new file mode 100644 index 000000000000..dfbfad9a9fda --- /dev/null +++ b/usr.sbin/fifolog/lib/getdate.y @@ -0,0 +1,876 @@ +%{ +/* +**  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> +** +*/ + +#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(void) +{ +    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; +    time_t		Start; +    time_t		tod; +    time_t nowtime; + +    yyInput = p; + +    (void)time (&nowtime); + +    if (! (tm = localtime (&nowtime))) +	return -1; + +    yyYear = tm->tm_year + 1900; +    yyMonth = tm->tm_mon + 1; +    yyDay = tm->tm_mday; +    yyTimezone = tm->tm_gmtoff; +    yyDSTmode = DSTmaybe; +    yyHour = 0; +    yyMinutes = 0; +    yySeconds = 0; +    yyMeridian = MER24; +    yyRelSeconds = 0; +    yyRelMonth = 0; +    yyHaveDate = 0; +    yyHaveDay = 0; +    yyHaveRel = 0; +    yyHaveTime = 0; +    yyHaveZone = 0; + +    if (yyparse() +     || yyHaveTime > 1 || yyHaveZone > 1 || yyHaveDate > 1 || yyHaveDay > 1) +	return -1; + +    if (yyHaveDate || yyHaveTime || yyHaveDay) { +	Start = Convert(yyMonth, yyDay, yyYear, yyHour, yyMinutes, yySeconds, +		    yyMeridian, yyDSTmode); +	if (Start < 0) +	    return -1; +    } +    else { +	Start = nowtime; +	if (!yyHaveRel) +	    Start -= ((tm->tm_hour * 60L + tm->tm_min) * 60L) + tm->tm_sec; +    } + +    Start += yyRelSeconds; +    Start += RelativeMonth(Start, yyRelMonth); + +    if (yyHaveDay && !yyHaveDate) { +	tod = RelativeDate(Start, yyDayOrdinal, yyDayNumber); +	Start += tod; +    } + +    /* Have to do *something* with a legitimate -1 so it's distinguishable +     * from the error return value.  (Alternately could set errno on error.) */ +    return Start == -1 ? 0 : Start; +} diff --git a/usr.sbin/fifolog/lib/libfifolog.h b/usr.sbin/fifolog/lib/libfifolog.h new file mode 100644 index 000000000000..239ad4974f1e --- /dev/null +++ b/usr.sbin/fifolog/lib/libfifolog.h @@ -0,0 +1,47 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * 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. + */ + +#include <sys/stdint.h> + +/* CREATORS */ +const char *fifolog_create(const char *fn, off_t size, ssize_t recsize); + +/* WRITERS */ + +#include "fifolog_write.h" + +/* 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); diff --git a/usr.sbin/fifolog/lib/libfifolog_int.h b/usr.sbin/fifolog/lib/libfifolog_int.h new file mode 100644 index 000000000000..42dac35aaaf2 --- /dev/null +++ b/usr.sbin/fifolog/lib/libfifolog_int.h @@ -0,0 +1,45 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * 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. + */ + +struct fifolog_file { +	unsigned			magic; +#define FIFOLOG_FILE_MAGIC		0x307ea50d + +	ssize_t				recsize; +	off_t				logsize; +	int				fd; + +	z_stream			*zs; + +	unsigned char			*recbuf; +}; + +const char *fifolog_int_open(struct fifolog_file **ff, const char *fname, int mode); +void fifolog_int_close(struct fifolog_file **ff); +int fifolog_int_read(const struct fifolog_file *ff, off_t recno); +const char *fifolog_int_findend(const struct fifolog_file *ff, off_t *last); diff --git a/usr.sbin/fifolog/lib/miniobj.h b/usr.sbin/fifolog/lib/miniobj.h new file mode 100644 index 000000000000..f643b207e7c8 --- /dev/null +++ b/usr.sbin/fifolog/lib/miniobj.h @@ -0,0 +1,74 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * 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. + */ + +#define ALLOC_OBJ(to, type_magic)					\ +	do {								\ +		(to) = calloc(1, sizeof *(to));				\ +		if ((to) != NULL)					\ +			(to)->magic = (type_magic);			\ +	} while (0) + +#define FREE_OBJ(to)							\ +	do {								\ +		(to)->magic = (0);					\ +		free(to);						\ +	} while (0) + +#define VALID_OBJ(ptr, type_magic)					\ +	((ptr) != NULL && (ptr)->magic == (type_magic)) + +#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 CHECK_OBJ_ORNULL(ptr, type_magic)				\ +	do {								\ +		if ((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) | 
