fifolog_int.c revision 185790
1176998Sphk/*- 2176998Sphk * Copyright (c) 2005-2008 Poul-Henning Kamp 3176998Sphk * All rights reserved. 4176998Sphk * 5176998Sphk * Redistribution and use in source and binary forms, with or without 6176998Sphk * modification, are permitted provided that the following conditions 7176998Sphk * are met: 8176998Sphk * 1. Redistributions of source code must retain the above copyright 9176998Sphk * notice, this list of conditions and the following disclaimer. 10176998Sphk * 2. Redistributions in binary form must reproduce the above copyright 11176998Sphk * notice, this list of conditions and the following disclaimer in the 12176998Sphk * documentation and/or other materials provided with the distribution. 13176998Sphk * 14176998Sphk * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15176998Sphk * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16176998Sphk * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17176998Sphk * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18176998Sphk * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19176998Sphk * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20176998Sphk * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21176998Sphk * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22176998Sphk * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23176998Sphk * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24176998Sphk * SUCH DAMAGE. 25176998Sphk * 26176998Sphk * $FreeBSD: head/usr.sbin/fifolog/lib/fifolog_int.c 185790 2008-12-09 09:25:03Z phk $ 27176998Sphk */ 28176998Sphk 29176998Sphk#include <assert.h> 30176998Sphk#include <errno.h> 31176998Sphk#include <fcntl.h> 32176998Sphk#include <stdlib.h> 33176998Sphk#include <string.h> 34176998Sphk#include <unistd.h> 35176998Sphk#include <zlib.h> 36176998Sphk 37176998Sphk#include <sys/disk.h> 38176998Sphk#include <sys/endian.h> 39176998Sphk#include <sys/stat.h> 40176998Sphk 41176998Sphk#include "miniobj.h" 42176998Sphk#include "fifolog.h" 43176998Sphk#include "libfifolog_int.h" 44176998Sphk 45176998Sphk/* 46176998Sphk * Memory handling for zlib 47176998Sphk */ 48176998Sphk 49176998Sphkstatic voidpf 50176998Sphkfifo_zalloc(voidpf opaque __unused, uInt items, uInt size) 51176998Sphk{ 52176998Sphk 53176998Sphk return calloc(items,size); 54176998Sphk} 55176998Sphk 56176998Sphkstatic void 57176998Sphkfifo_zfree(voidpf opaque __unused, voidpf address) 58176998Sphk{ 59176998Sphk 60176998Sphk free(address); 61176998Sphk} 62176998Sphk 63176998Sphk/* 64176998Sphk * Open a fifolog file or partition for reading or writing. 65176998Sphk * 66176998Sphk * Return value is NULL for success or a error description string to 67176998Sphk * be augmented by errno if non-zero. 68176998Sphk * 69176998Sphk * The second function is just an error-handling wrapper around the 70176998Sphk * first which, does the actual work. 71176998Sphk */ 72176998Sphk 73176998Sphkstatic const char * 74176998Sphkfifolog_int_open_i(struct fifolog_file *f, const char *fname, int mode) 75176998Sphk{ 76176998Sphk struct stat st; 77176998Sphk unsigned u; 78176998Sphk int i; 79176998Sphk 80176998Sphk f->fd = open(fname, mode ? O_RDWR : O_RDONLY); 81176998Sphk if (f->fd < 0) 82176998Sphk return ("Cannot open"); 83176998Sphk 84176998Sphk /* Determine initial record size guesstimate */ 85176998Sphk i = ioctl(f->fd, DIOCGSECTORSIZE, &f->recsize); 86176998Sphk if (i != 0 && errno != ENOTTY) 87176998Sphk return ("ioctl(DIOCGSECTORSIZE) failed"); 88176998Sphk 89176998Sphk if (i != 0) { 90176998Sphk i = fstat(f->fd, &st); 91176998Sphk if (!S_ISREG(st.st_mode)) 92176998Sphk return ("Neither disk nor regular file"); 93176998Sphk f->recsize = 512; 94176998Sphk f->logsize = st.st_size; 95176998Sphk } else if (f->recsize < 64) { 96176998Sphk return ("Disk device sectorsize smaller than 64"); 97176998Sphk } else { 98176998Sphk i = ioctl(f->fd, DIOCGMEDIASIZE, &f->logsize); 99176998Sphk if (i < 0 && errno != ENOTTY) 100176998Sphk return ("ioctl(DIOCGMEDIASIZE) failed"); 101176998Sphk } 102176998Sphk 103176998Sphk /* Allocate a record buffer */ 104176998Sphk f->recbuf = malloc(f->recsize); 105176998Sphk if (f->recbuf == NULL) 106176998Sphk return ("Cannot malloc"); 107176998Sphk 108176998Sphk /* Read and validate the label sector */ 109176998Sphk i = pread(f->fd, f->recbuf, f->recsize, 0); 110176998Sphk if (i < 0 || i < (int)f->recsize) 111176998Sphk return ("Read error, first sector"); 112176998Sphk 113176998Sphk errno = 0; 114176998Sphk if (memcmp(f->recbuf, FIFOLOG_FMT_MAGIC, strlen(FIFOLOG_FMT_MAGIC) + 1)) 115176998Sphk return ("Wrong or missing magic string"); 116176998Sphk 117176998Sphk u = be32dec(f->recbuf + FIFOLOG_OFF_BS); 118176998Sphk if (u < 64) 119176998Sphk return ("Wrong record size in header (<64)"); 120176998Sphk 121176998Sphk if ((off_t)u >= f->logsize) 122176998Sphk return ("Record size in header bigger than fifolog"); 123176998Sphk 124176998Sphk f->recsize = u; 125176998Sphk 126176998Sphk /* Reallocate the buffer to correct size if necessary */ 127176998Sphk if (u != f->recsize) { 128176998Sphk free(f->recbuf); 129176998Sphk f->recbuf = NULL; 130176998Sphk f->recsize = u; 131176998Sphk f->recbuf = malloc(f->recsize); 132176998Sphk if (f->recbuf == NULL) 133176998Sphk return ("Cannot malloc"); 134176998Sphk } 135176998Sphk 136176998Sphk /* Calculate number of records in fifolog */ 137176998Sphk f->logsize /= u; 138176998Sphk if (f->logsize < 10) 139176998Sphk return ("less than 10 records in fifolog"); 140176998Sphk 141176998Sphk f->logsize--; /* the label record */ 142176998Sphk 143176998Sphk /* Initialize zlib handling */ 144176998Sphk 145176998Sphk f->zs = calloc(sizeof *f->zs, 1); 146176998Sphk if (f->zs == NULL) 147176998Sphk return ("cannot malloc"); 148176998Sphk f->zs->zalloc = fifo_zalloc; 149176998Sphk f->zs->zfree = fifo_zfree; 150176998Sphk 151176998Sphk return (NULL); 152176998Sphk} 153176998Sphk 154176998Sphkconst char * 155176998Sphkfifolog_int_open(struct fifolog_file **ff, const char *fname, int mode) 156176998Sphk{ 157176998Sphk struct fifolog_file fs, *f; 158176998Sphk const char *retval; 159176998Sphk int e; 160176998Sphk 161176998Sphk f = &fs; 162176998Sphk memset(f, 0, sizeof *f); 163176998Sphk f->fd = -1; 164176998Sphk retval = fifolog_int_open_i(f, fname, mode); 165176998Sphk e = errno; 166176998Sphk if (retval == NULL) { 167176998Sphk *ff = malloc(sizeof *f); 168176998Sphk if (*ff != NULL) { 169176998Sphk memcpy(*ff, f, sizeof *f); 170176998Sphk (*ff)->magic = FIFOLOG_FILE_MAGIC; 171176998Sphk return (retval); 172176998Sphk } 173176998Sphk } 174176998Sphk fifolog_int_close(&f); 175176998Sphk errno = e; 176176998Sphk return (retval); 177176998Sphk} 178176998Sphk 179176998Sphkvoid 180176998Sphkfifolog_int_close(struct fifolog_file **ff) 181176998Sphk{ 182176998Sphk struct fifolog_file *f; 183176998Sphk 184176998Sphk f = *ff; 185176998Sphk *ff = NULL; 186176998Sphk if (f == NULL) 187176998Sphk return; 188176998Sphk 189176998Sphk if (f->fd >= 0) 190176998Sphk (void)close(f->fd); 191176998Sphk if (f->zs != NULL) 192176998Sphk free(f->zs); 193176998Sphk if (f->recbuf != NULL) 194176998Sphk free(f->recbuf); 195176998Sphk} 196176998Sphk 197176998Sphkstatic void 198176998Sphkfifolog_int_file_assert(const struct fifolog_file *ff) 199176998Sphk{ 200176998Sphk 201176998Sphk CHECK_OBJ_NOTNULL(ff, FIFOLOG_FILE_MAGIC); 202176998Sphk assert(ff->fd >= 0); 203176998Sphk assert(ff->recbuf != NULL); 204176998Sphk} 205176998Sphk 206176998Sphk 207176998Sphk/* 208176998Sphk * Read a record. 209176998Sphk * 210176998Sphk * Return zero on success 211176998Sphk */ 212176998Sphk 213176998Sphkint 214176998Sphkfifolog_int_read(const struct fifolog_file *ff, off_t recno) 215176998Sphk{ 216176998Sphk int i; 217176998Sphk 218176998Sphk fifolog_int_file_assert(ff); 219176998Sphk if (recno >= ff->logsize) 220176998Sphk return (-1); 221176998Sphk recno++; /* label sector */ 222176998Sphk i = pread(ff->fd, ff->recbuf, ff->recsize, recno * ff->recsize); 223176998Sphk if (i < 0) 224185790Sphk return (-2); 225176998Sphk if (i != (int)ff->recsize) 226185790Sphk return (-3); 227176998Sphk return (0); 228176998Sphk} 229176998Sphk 230176998Sphk/* 231176998Sphk * Find the last written record in the fifolog. 232176998Sphk * 233176998Sphk * Return is error string or NULL on success 234176998Sphk */ 235176998Sphk 236176998Sphkconst char * 237176998Sphkfifolog_int_findend(const struct fifolog_file *ff, off_t *last) 238176998Sphk{ 239176998Sphk off_t o, s; 240176998Sphk int e; 241176998Sphk unsigned seq0, seq; 242176998Sphk 243176998Sphk fifolog_int_file_assert(ff); 244176998Sphk 245176998Sphk o = 0; 246176998Sphk e = fifolog_int_read(ff, o); 247176998Sphk if (e) 248176998Sphk return("Read error, first record"); 249176998Sphk 250176998Sphk seq0 = be32dec(ff->recbuf); 251176998Sphk 252176998Sphk /* If the first records sequence is zero, the fifolog is empty */ 253176998Sphk if (seq0 == 0) { 254176998Sphk *last = o; 255176998Sphk return (NULL); 256176998Sphk } 257176998Sphk 258176998Sphk /* Do a binary search for a discontinuity in the sequence numbers */ 259176998Sphk s = ff->logsize / 2; 260176998Sphk do { 261176998Sphk e = fifolog_int_read(ff, o + s); 262176998Sphk if (e) 263176998Sphk return ("Read error while searching"); 264176998Sphk seq = be32dec(ff->recbuf); 265176998Sphk if (seq == seq0 + s) { 266176998Sphk o += s; 267176998Sphk seq0 = seq; 268176998Sphk } 269176998Sphk s /= 2; 270176998Sphk assert(o < ff->logsize); 271176998Sphk } while (s > 0); 272176998Sphk 273176998Sphk *last = o; 274176998Sphk return (NULL); 275176998Sphk} 276