xref: /freebsd/usr.sbin/fifolog/lib/fifolog_int.c (revision b3e76948)
1662cb04cSPoul-Henning Kamp /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
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 
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 *
fifolog_int_open_i(struct fifolog_file * f,const char * fname,int mode)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 *
fifolog_int_open(struct fifolog_file ** ff,const char * fname,int mode)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
fifolog_int_close(struct fifolog_file ** ff)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
fifolog_int_file_assert(const struct fifolog_file * ff)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
fifolog_int_read(const struct fifolog_file * ff,off_t recno)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 *
fifolog_int_findend(const struct fifolog_file * ff,off_t * last)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