1662cb04cSPoul-Henning Kamp /*- 2662cb04cSPoul-Henning Kamp * Copyright (c) 2005-2008 Poul-Henning Kamp 3662cb04cSPoul-Henning Kamp * All rights reserved. 4662cb04cSPoul-Henning Kamp * 5662cb04cSPoul-Henning Kamp * Redistribution and use in source and binary forms, with or without 6662cb04cSPoul-Henning Kamp * modification, are permitted provided that the following conditions 7662cb04cSPoul-Henning Kamp * are met: 8662cb04cSPoul-Henning Kamp * 1. Redistributions of source code must retain the above copyright 9662cb04cSPoul-Henning Kamp * notice, this list of conditions and the following disclaimer. 10662cb04cSPoul-Henning Kamp * 2. Redistributions in binary form must reproduce the above copyright 11662cb04cSPoul-Henning Kamp * notice, this list of conditions and the following disclaimer in the 12662cb04cSPoul-Henning Kamp * documentation and/or other materials provided with the distribution. 13662cb04cSPoul-Henning Kamp * 14662cb04cSPoul-Henning Kamp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15662cb04cSPoul-Henning Kamp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16662cb04cSPoul-Henning Kamp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17662cb04cSPoul-Henning Kamp * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18662cb04cSPoul-Henning Kamp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19662cb04cSPoul-Henning Kamp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20662cb04cSPoul-Henning Kamp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21662cb04cSPoul-Henning Kamp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22662cb04cSPoul-Henning Kamp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23662cb04cSPoul-Henning Kamp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24662cb04cSPoul-Henning Kamp * SUCH DAMAGE. 25662cb04cSPoul-Henning Kamp * 26662cb04cSPoul-Henning Kamp * $FreeBSD$ 27662cb04cSPoul-Henning Kamp */ 28662cb04cSPoul-Henning Kamp 29662cb04cSPoul-Henning Kamp #include <assert.h> 30662cb04cSPoul-Henning Kamp #include <errno.h> 31662cb04cSPoul-Henning Kamp #include <fcntl.h> 32662cb04cSPoul-Henning Kamp #include <stdlib.h> 33662cb04cSPoul-Henning Kamp #include <string.h> 34662cb04cSPoul-Henning Kamp #include <unistd.h> 35662cb04cSPoul-Henning Kamp #include <zlib.h> 36662cb04cSPoul-Henning Kamp 37662cb04cSPoul-Henning Kamp #include <sys/disk.h> 38662cb04cSPoul-Henning Kamp #include <sys/endian.h> 39662cb04cSPoul-Henning Kamp #include <sys/stat.h> 40662cb04cSPoul-Henning Kamp 41662cb04cSPoul-Henning Kamp #include "miniobj.h" 42662cb04cSPoul-Henning Kamp #include "fifolog.h" 43662cb04cSPoul-Henning Kamp #include "libfifolog_int.h" 44662cb04cSPoul-Henning Kamp 45662cb04cSPoul-Henning Kamp /* 46662cb04cSPoul-Henning Kamp * Open a fifolog file or partition for reading or writing. 47662cb04cSPoul-Henning Kamp * 48662cb04cSPoul-Henning Kamp * Return value is NULL for success or a error description string to 49662cb04cSPoul-Henning Kamp * be augmented by errno if non-zero. 50662cb04cSPoul-Henning Kamp * 51662cb04cSPoul-Henning Kamp * The second function is just an error-handling wrapper around the 52662cb04cSPoul-Henning Kamp * first which, does the actual work. 53662cb04cSPoul-Henning Kamp */ 54662cb04cSPoul-Henning Kamp 55662cb04cSPoul-Henning Kamp static const char * 56662cb04cSPoul-Henning Kamp fifolog_int_open_i(struct fifolog_file *f, const char *fname, int mode) 57662cb04cSPoul-Henning Kamp { 58662cb04cSPoul-Henning Kamp struct stat st; 592f203e81SPoul-Henning Kamp ssize_t u; 60662cb04cSPoul-Henning Kamp int i; 61662cb04cSPoul-Henning Kamp 62662cb04cSPoul-Henning Kamp f->fd = open(fname, mode ? O_RDWR : O_RDONLY); 63662cb04cSPoul-Henning Kamp if (f->fd < 0) 64662cb04cSPoul-Henning Kamp return ("Cannot open"); 65662cb04cSPoul-Henning Kamp 66662cb04cSPoul-Henning Kamp /* Determine initial record size guesstimate */ 67662cb04cSPoul-Henning Kamp i = ioctl(f->fd, DIOCGSECTORSIZE, &f->recsize); 68662cb04cSPoul-Henning Kamp if (i != 0 && errno != ENOTTY) 69662cb04cSPoul-Henning Kamp return ("ioctl(DIOCGSECTORSIZE) failed"); 70662cb04cSPoul-Henning Kamp 71662cb04cSPoul-Henning Kamp if (i != 0) { 72662cb04cSPoul-Henning Kamp i = fstat(f->fd, &st); 7354a3365dSPoul-Henning Kamp assert(i == 0); 74662cb04cSPoul-Henning Kamp if (!S_ISREG(st.st_mode)) 75662cb04cSPoul-Henning Kamp return ("Neither disk nor regular file"); 76662cb04cSPoul-Henning Kamp f->recsize = 512; 77662cb04cSPoul-Henning Kamp f->logsize = st.st_size; 78662cb04cSPoul-Henning Kamp } else if (f->recsize < 64) { 79662cb04cSPoul-Henning Kamp return ("Disk device sectorsize smaller than 64"); 80662cb04cSPoul-Henning Kamp } else { 81662cb04cSPoul-Henning Kamp i = ioctl(f->fd, DIOCGMEDIASIZE, &f->logsize); 82662cb04cSPoul-Henning Kamp if (i < 0 && errno != ENOTTY) 83662cb04cSPoul-Henning Kamp return ("ioctl(DIOCGMEDIASIZE) failed"); 84662cb04cSPoul-Henning Kamp } 85662cb04cSPoul-Henning Kamp 86662cb04cSPoul-Henning Kamp /* Allocate a record buffer */ 87662cb04cSPoul-Henning Kamp f->recbuf = malloc(f->recsize); 88662cb04cSPoul-Henning Kamp if (f->recbuf == NULL) 89662cb04cSPoul-Henning Kamp return ("Cannot malloc"); 90662cb04cSPoul-Henning Kamp 91662cb04cSPoul-Henning Kamp /* Read and validate the label sector */ 92662cb04cSPoul-Henning Kamp i = pread(f->fd, f->recbuf, f->recsize, 0); 93662cb04cSPoul-Henning Kamp if (i < 0 || i < (int)f->recsize) 94662cb04cSPoul-Henning Kamp return ("Read error, first sector"); 95662cb04cSPoul-Henning Kamp 96662cb04cSPoul-Henning Kamp errno = 0; 97662cb04cSPoul-Henning Kamp if (memcmp(f->recbuf, FIFOLOG_FMT_MAGIC, strlen(FIFOLOG_FMT_MAGIC) + 1)) 98662cb04cSPoul-Henning Kamp return ("Wrong or missing magic string"); 99662cb04cSPoul-Henning Kamp 100662cb04cSPoul-Henning Kamp u = be32dec(f->recbuf + FIFOLOG_OFF_BS); 101662cb04cSPoul-Henning Kamp if (u < 64) 102662cb04cSPoul-Henning Kamp return ("Wrong record size in header (<64)"); 103662cb04cSPoul-Henning Kamp 104662cb04cSPoul-Henning Kamp if ((off_t)u >= f->logsize) 105662cb04cSPoul-Henning Kamp return ("Record size in header bigger than fifolog"); 106662cb04cSPoul-Henning Kamp 107662cb04cSPoul-Henning Kamp f->recsize = u; 108662cb04cSPoul-Henning Kamp 109662cb04cSPoul-Henning Kamp /* Reallocate the buffer to correct size if necessary */ 110662cb04cSPoul-Henning Kamp if (u != f->recsize) { 111662cb04cSPoul-Henning Kamp free(f->recbuf); 112662cb04cSPoul-Henning Kamp f->recbuf = NULL; 113662cb04cSPoul-Henning Kamp f->recsize = u; 114662cb04cSPoul-Henning Kamp f->recbuf = malloc(f->recsize); 115662cb04cSPoul-Henning Kamp if (f->recbuf == NULL) 116662cb04cSPoul-Henning Kamp return ("Cannot malloc"); 117662cb04cSPoul-Henning Kamp } 118662cb04cSPoul-Henning Kamp 119662cb04cSPoul-Henning Kamp /* Calculate number of records in fifolog */ 120662cb04cSPoul-Henning Kamp f->logsize /= u; 121662cb04cSPoul-Henning Kamp if (f->logsize < 10) 122662cb04cSPoul-Henning Kamp return ("less than 10 records in fifolog"); 123662cb04cSPoul-Henning Kamp 124662cb04cSPoul-Henning Kamp f->logsize--; /* the label record */ 125662cb04cSPoul-Henning Kamp 126662cb04cSPoul-Henning Kamp /* Initialize zlib handling */ 127662cb04cSPoul-Henning Kamp 1285ddd0f16SMarcelo Araujo f->zs = calloc(1, sizeof(*f->zs)); 129662cb04cSPoul-Henning Kamp if (f->zs == NULL) 130662cb04cSPoul-Henning Kamp return ("cannot malloc"); 131662cb04cSPoul-Henning Kamp 132662cb04cSPoul-Henning Kamp return (NULL); 133662cb04cSPoul-Henning Kamp } 134662cb04cSPoul-Henning Kamp 135662cb04cSPoul-Henning Kamp const char * 136662cb04cSPoul-Henning Kamp fifolog_int_open(struct fifolog_file **ff, const char *fname, int mode) 137662cb04cSPoul-Henning Kamp { 138662cb04cSPoul-Henning Kamp struct fifolog_file fs, *f; 139662cb04cSPoul-Henning Kamp const char *retval; 140662cb04cSPoul-Henning Kamp int e; 141662cb04cSPoul-Henning Kamp 142662cb04cSPoul-Henning Kamp f = &fs; 143662cb04cSPoul-Henning Kamp memset(f, 0, sizeof *f); 144662cb04cSPoul-Henning Kamp f->fd = -1; 145662cb04cSPoul-Henning Kamp retval = fifolog_int_open_i(f, fname, mode); 146662cb04cSPoul-Henning Kamp e = errno; 147662cb04cSPoul-Henning Kamp if (retval == NULL) { 148662cb04cSPoul-Henning Kamp *ff = malloc(sizeof *f); 149662cb04cSPoul-Henning Kamp if (*ff != NULL) { 150662cb04cSPoul-Henning Kamp memcpy(*ff, f, sizeof *f); 151662cb04cSPoul-Henning Kamp (*ff)->magic = FIFOLOG_FILE_MAGIC; 152662cb04cSPoul-Henning Kamp return (retval); 153662cb04cSPoul-Henning Kamp } 154662cb04cSPoul-Henning Kamp } 155662cb04cSPoul-Henning Kamp fifolog_int_close(&f); 156662cb04cSPoul-Henning Kamp errno = e; 157662cb04cSPoul-Henning Kamp return (retval); 158662cb04cSPoul-Henning Kamp } 159662cb04cSPoul-Henning Kamp 160662cb04cSPoul-Henning Kamp void 161662cb04cSPoul-Henning Kamp fifolog_int_close(struct fifolog_file **ff) 162662cb04cSPoul-Henning Kamp { 163662cb04cSPoul-Henning Kamp struct fifolog_file *f; 164662cb04cSPoul-Henning Kamp 165662cb04cSPoul-Henning Kamp f = *ff; 166662cb04cSPoul-Henning Kamp *ff = NULL; 167662cb04cSPoul-Henning Kamp if (f == NULL) 168662cb04cSPoul-Henning Kamp return; 169662cb04cSPoul-Henning Kamp 170662cb04cSPoul-Henning Kamp if (f->fd >= 0) 171662cb04cSPoul-Henning Kamp (void)close(f->fd); 172662cb04cSPoul-Henning Kamp if (f->zs != NULL) 173662cb04cSPoul-Henning Kamp free(f->zs); 174662cb04cSPoul-Henning Kamp if (f->recbuf != NULL) 175662cb04cSPoul-Henning Kamp free(f->recbuf); 176662cb04cSPoul-Henning Kamp } 177662cb04cSPoul-Henning Kamp 178662cb04cSPoul-Henning Kamp static void 179662cb04cSPoul-Henning Kamp fifolog_int_file_assert(const struct fifolog_file *ff) 180662cb04cSPoul-Henning Kamp { 181662cb04cSPoul-Henning Kamp 182662cb04cSPoul-Henning Kamp CHECK_OBJ_NOTNULL(ff, FIFOLOG_FILE_MAGIC); 183662cb04cSPoul-Henning Kamp assert(ff->fd >= 0); 184662cb04cSPoul-Henning Kamp assert(ff->recbuf != NULL); 185662cb04cSPoul-Henning Kamp } 186662cb04cSPoul-Henning Kamp 187662cb04cSPoul-Henning Kamp 188662cb04cSPoul-Henning Kamp /* 189662cb04cSPoul-Henning Kamp * Read a record. 190662cb04cSPoul-Henning Kamp * 191662cb04cSPoul-Henning Kamp * Return zero on success 192662cb04cSPoul-Henning Kamp */ 193662cb04cSPoul-Henning Kamp 194662cb04cSPoul-Henning Kamp int 195662cb04cSPoul-Henning Kamp fifolog_int_read(const struct fifolog_file *ff, off_t recno) 196662cb04cSPoul-Henning Kamp { 197662cb04cSPoul-Henning Kamp int i; 198662cb04cSPoul-Henning Kamp 199662cb04cSPoul-Henning Kamp fifolog_int_file_assert(ff); 200662cb04cSPoul-Henning Kamp if (recno >= ff->logsize) 201662cb04cSPoul-Henning Kamp return (-1); 202662cb04cSPoul-Henning Kamp recno++; /* label sector */ 203662cb04cSPoul-Henning Kamp i = pread(ff->fd, ff->recbuf, ff->recsize, recno * ff->recsize); 204662cb04cSPoul-Henning Kamp if (i < 0) 205ba2b5429SPoul-Henning Kamp return (-2); 206662cb04cSPoul-Henning Kamp if (i != (int)ff->recsize) 207ba2b5429SPoul-Henning Kamp return (-3); 208662cb04cSPoul-Henning Kamp return (0); 209662cb04cSPoul-Henning Kamp } 210662cb04cSPoul-Henning Kamp 211662cb04cSPoul-Henning Kamp /* 212662cb04cSPoul-Henning Kamp * Find the last written record in the fifolog. 213662cb04cSPoul-Henning Kamp * 214662cb04cSPoul-Henning Kamp * Return is error string or NULL on success 215662cb04cSPoul-Henning Kamp */ 216662cb04cSPoul-Henning Kamp 217662cb04cSPoul-Henning Kamp const char * 218662cb04cSPoul-Henning Kamp fifolog_int_findend(const struct fifolog_file *ff, off_t *last) 219662cb04cSPoul-Henning Kamp { 220662cb04cSPoul-Henning Kamp off_t o, s; 221662cb04cSPoul-Henning Kamp int e; 222662cb04cSPoul-Henning Kamp unsigned seq0, seq; 223662cb04cSPoul-Henning Kamp 224662cb04cSPoul-Henning Kamp fifolog_int_file_assert(ff); 225662cb04cSPoul-Henning Kamp 226662cb04cSPoul-Henning Kamp o = 0; 227662cb04cSPoul-Henning Kamp e = fifolog_int_read(ff, o); 228662cb04cSPoul-Henning Kamp if (e) 229662cb04cSPoul-Henning Kamp return("Read error, first record"); 230662cb04cSPoul-Henning Kamp 231662cb04cSPoul-Henning Kamp seq0 = be32dec(ff->recbuf); 232662cb04cSPoul-Henning Kamp 233662cb04cSPoul-Henning Kamp /* If the first records sequence is zero, the fifolog is empty */ 234662cb04cSPoul-Henning Kamp if (seq0 == 0) { 235662cb04cSPoul-Henning Kamp *last = o; 236662cb04cSPoul-Henning Kamp return (NULL); 237662cb04cSPoul-Henning Kamp } 238662cb04cSPoul-Henning Kamp 239662cb04cSPoul-Henning Kamp /* Do a binary search for a discontinuity in the sequence numbers */ 240662cb04cSPoul-Henning Kamp s = ff->logsize / 2; 241662cb04cSPoul-Henning Kamp do { 242662cb04cSPoul-Henning Kamp e = fifolog_int_read(ff, o + s); 243662cb04cSPoul-Henning Kamp if (e) 244662cb04cSPoul-Henning Kamp return ("Read error while searching"); 245662cb04cSPoul-Henning Kamp seq = be32dec(ff->recbuf); 246662cb04cSPoul-Henning Kamp if (seq == seq0 + s) { 247662cb04cSPoul-Henning Kamp o += s; 248662cb04cSPoul-Henning Kamp seq0 = seq; 249662cb04cSPoul-Henning Kamp } 250662cb04cSPoul-Henning Kamp s /= 2; 251662cb04cSPoul-Henning Kamp assert(o < ff->logsize); 252662cb04cSPoul-Henning Kamp } while (s > 0); 253662cb04cSPoul-Henning Kamp 254662cb04cSPoul-Henning Kamp *last = o; 255662cb04cSPoul-Henning Kamp return (NULL); 256662cb04cSPoul-Henning Kamp } 257