fifolog_int.c revision 219094
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 219094 2011-02-28 08:59:35Z 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 * Open a fifolog file or partition for reading or writing. 47176998Sphk * 48176998Sphk * Return value is NULL for success or a error description string to 49176998Sphk * be augmented by errno if non-zero. 50176998Sphk * 51219027Sphk * The second function is just an error-handling wrapper around the 52176998Sphk * first which, does the actual work. 53176998Sphk */ 54176998Sphk 55176998Sphkstatic const char * 56176998Sphkfifolog_int_open_i(struct fifolog_file *f, const char *fname, int mode) 57176998Sphk{ 58176998Sphk struct stat st; 59176998Sphk unsigned u; 60176998Sphk int i; 61176998Sphk 62176998Sphk f->fd = open(fname, mode ? O_RDWR : O_RDONLY); 63176998Sphk if (f->fd < 0) 64176998Sphk return ("Cannot open"); 65176998Sphk 66176998Sphk /* Determine initial record size guesstimate */ 67176998Sphk i = ioctl(f->fd, DIOCGSECTORSIZE, &f->recsize); 68176998Sphk if (i != 0 && errno != ENOTTY) 69176998Sphk return ("ioctl(DIOCGSECTORSIZE) failed"); 70176998Sphk 71176998Sphk if (i != 0) { 72176998Sphk i = fstat(f->fd, &st); 73219094Sphk assert(i == 0); 74219027Sphk if (!S_ISREG(st.st_mode)) 75176998Sphk return ("Neither disk nor regular file"); 76176998Sphk f->recsize = 512; 77176998Sphk f->logsize = st.st_size; 78176998Sphk } else if (f->recsize < 64) { 79176998Sphk return ("Disk device sectorsize smaller than 64"); 80176998Sphk } else { 81176998Sphk i = ioctl(f->fd, DIOCGMEDIASIZE, &f->logsize); 82176998Sphk if (i < 0 && errno != ENOTTY) 83176998Sphk return ("ioctl(DIOCGMEDIASIZE) failed"); 84176998Sphk } 85176998Sphk 86176998Sphk /* Allocate a record buffer */ 87176998Sphk f->recbuf = malloc(f->recsize); 88176998Sphk if (f->recbuf == NULL) 89176998Sphk return ("Cannot malloc"); 90176998Sphk 91176998Sphk /* Read and validate the label sector */ 92176998Sphk i = pread(f->fd, f->recbuf, f->recsize, 0); 93176998Sphk if (i < 0 || i < (int)f->recsize) 94176998Sphk return ("Read error, first sector"); 95176998Sphk 96176998Sphk errno = 0; 97176998Sphk if (memcmp(f->recbuf, FIFOLOG_FMT_MAGIC, strlen(FIFOLOG_FMT_MAGIC) + 1)) 98176998Sphk return ("Wrong or missing magic string"); 99176998Sphk 100176998Sphk u = be32dec(f->recbuf + FIFOLOG_OFF_BS); 101176998Sphk if (u < 64) 102176998Sphk return ("Wrong record size in header (<64)"); 103176998Sphk 104176998Sphk if ((off_t)u >= f->logsize) 105176998Sphk return ("Record size in header bigger than fifolog"); 106176998Sphk 107176998Sphk f->recsize = u; 108176998Sphk 109176998Sphk /* Reallocate the buffer to correct size if necessary */ 110176998Sphk if (u != f->recsize) { 111176998Sphk free(f->recbuf); 112176998Sphk f->recbuf = NULL; 113176998Sphk f->recsize = u; 114176998Sphk f->recbuf = malloc(f->recsize); 115176998Sphk if (f->recbuf == NULL) 116176998Sphk return ("Cannot malloc"); 117176998Sphk } 118176998Sphk 119176998Sphk /* Calculate number of records in fifolog */ 120176998Sphk f->logsize /= u; 121176998Sphk if (f->logsize < 10) 122176998Sphk return ("less than 10 records in fifolog"); 123176998Sphk 124176998Sphk f->logsize--; /* the label record */ 125176998Sphk 126176998Sphk /* Initialize zlib handling */ 127176998Sphk 128176998Sphk f->zs = calloc(sizeof *f->zs, 1); 129176998Sphk if (f->zs == NULL) 130176998Sphk return ("cannot malloc"); 131176998Sphk 132176998Sphk return (NULL); 133176998Sphk} 134176998Sphk 135176998Sphkconst char * 136176998Sphkfifolog_int_open(struct fifolog_file **ff, const char *fname, int mode) 137176998Sphk{ 138176998Sphk struct fifolog_file fs, *f; 139176998Sphk const char *retval; 140176998Sphk int e; 141176998Sphk 142176998Sphk f = &fs; 143176998Sphk memset(f, 0, sizeof *f); 144176998Sphk f->fd = -1; 145176998Sphk retval = fifolog_int_open_i(f, fname, mode); 146176998Sphk e = errno; 147176998Sphk if (retval == NULL) { 148176998Sphk *ff = malloc(sizeof *f); 149176998Sphk if (*ff != NULL) { 150176998Sphk memcpy(*ff, f, sizeof *f); 151176998Sphk (*ff)->magic = FIFOLOG_FILE_MAGIC; 152176998Sphk return (retval); 153176998Sphk } 154176998Sphk } 155176998Sphk fifolog_int_close(&f); 156176998Sphk errno = e; 157176998Sphk return (retval); 158176998Sphk} 159176998Sphk 160176998Sphkvoid 161176998Sphkfifolog_int_close(struct fifolog_file **ff) 162176998Sphk{ 163176998Sphk struct fifolog_file *f; 164176998Sphk 165176998Sphk f = *ff; 166176998Sphk *ff = NULL; 167176998Sphk if (f == NULL) 168176998Sphk return; 169176998Sphk 170176998Sphk if (f->fd >= 0) 171176998Sphk (void)close(f->fd); 172176998Sphk if (f->zs != NULL) 173176998Sphk free(f->zs); 174176998Sphk if (f->recbuf != NULL) 175176998Sphk free(f->recbuf); 176176998Sphk} 177176998Sphk 178176998Sphkstatic void 179176998Sphkfifolog_int_file_assert(const struct fifolog_file *ff) 180176998Sphk{ 181176998Sphk 182176998Sphk CHECK_OBJ_NOTNULL(ff, FIFOLOG_FILE_MAGIC); 183176998Sphk assert(ff->fd >= 0); 184176998Sphk assert(ff->recbuf != NULL); 185176998Sphk} 186176998Sphk 187176998Sphk 188176998Sphk/* 189176998Sphk * Read a record. 190176998Sphk * 191176998Sphk * Return zero on success 192176998Sphk */ 193176998Sphk 194176998Sphkint 195176998Sphkfifolog_int_read(const struct fifolog_file *ff, off_t recno) 196176998Sphk{ 197176998Sphk int i; 198176998Sphk 199176998Sphk fifolog_int_file_assert(ff); 200176998Sphk if (recno >= ff->logsize) 201176998Sphk return (-1); 202176998Sphk recno++; /* label sector */ 203176998Sphk i = pread(ff->fd, ff->recbuf, ff->recsize, recno * ff->recsize); 204176998Sphk if (i < 0) 205185790Sphk return (-2); 206176998Sphk if (i != (int)ff->recsize) 207185790Sphk return (-3); 208176998Sphk return (0); 209176998Sphk} 210176998Sphk 211176998Sphk/* 212176998Sphk * Find the last written record in the fifolog. 213176998Sphk * 214176998Sphk * Return is error string or NULL on success 215176998Sphk */ 216176998Sphk 217176998Sphkconst char * 218176998Sphkfifolog_int_findend(const struct fifolog_file *ff, off_t *last) 219176998Sphk{ 220176998Sphk off_t o, s; 221176998Sphk int e; 222176998Sphk unsigned seq0, seq; 223176998Sphk 224176998Sphk fifolog_int_file_assert(ff); 225176998Sphk 226176998Sphk o = 0; 227176998Sphk e = fifolog_int_read(ff, o); 228176998Sphk if (e) 229176998Sphk return("Read error, first record"); 230176998Sphk 231176998Sphk seq0 = be32dec(ff->recbuf); 232176998Sphk 233176998Sphk /* If the first records sequence is zero, the fifolog is empty */ 234176998Sphk if (seq0 == 0) { 235176998Sphk *last = o; 236176998Sphk return (NULL); 237176998Sphk } 238176998Sphk 239176998Sphk /* Do a binary search for a discontinuity in the sequence numbers */ 240176998Sphk s = ff->logsize / 2; 241176998Sphk do { 242176998Sphk e = fifolog_int_read(ff, o + s); 243176998Sphk if (e) 244176998Sphk return ("Read error while searching"); 245176998Sphk seq = be32dec(ff->recbuf); 246176998Sphk if (seq == seq0 + s) { 247176998Sphk o += s; 248176998Sphk seq0 = seq; 249176998Sphk } 250176998Sphk s /= 2; 251176998Sphk assert(o < ff->logsize); 252176998Sphk } while (s > 0); 253176998Sphk 254176998Sphk *last = o; 255176998Sphk return (NULL); 256176998Sphk} 257