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