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