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