1b973f2b91343554586da3c952c63c2369acd879whr/*
2b973f2b91343554586da3c952c63c2369acd879whr * Copyright (c) 2000 Silicon Graphics, Inc.  All Rights Reserved.
345a8ba0302fa0632410b2f100f92701651dd7a0fvapier *
4b973f2b91343554586da3c952c63c2369acd879whr * This program is free software; you can redistribute it and/or modify it
5b973f2b91343554586da3c952c63c2369acd879whr * under the terms of version 2 of the GNU General Public License as
6b973f2b91343554586da3c952c63c2369acd879whr * published by the Free Software Foundation.
745a8ba0302fa0632410b2f100f92701651dd7a0fvapier *
8b973f2b91343554586da3c952c63c2369acd879whr * This program is distributed in the hope that it would be useful, but
9b973f2b91343554586da3c952c63c2369acd879whr * WITHOUT ANY WARRANTY; without even the implied warranty of
10b973f2b91343554586da3c952c63c2369acd879whr * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
1145a8ba0302fa0632410b2f100f92701651dd7a0fvapier *
12b973f2b91343554586da3c952c63c2369acd879whr * Further, this software is distributed without any warranty that it is
13b973f2b91343554586da3c952c63c2369acd879whr * free of the rightful claim of any third person regarding infringement
14b973f2b91343554586da3c952c63c2369acd879whr * or the like.  Any license provided herein, whether implied or
15b973f2b91343554586da3c952c63c2369acd879whr * otherwise, applies only to this software file.  Patent licenses, if
16b973f2b91343554586da3c952c63c2369acd879whr * any, provided herein do not apply to combinations of this program with
17b973f2b91343554586da3c952c63c2369acd879whr * other software, or any other product whatsoever.
1845a8ba0302fa0632410b2f100f92701651dd7a0fvapier *
19b973f2b91343554586da3c952c63c2369acd879whr * You should have received a copy of the GNU General Public License along
20fed9641096e27f79a0f2d9adfe9839dd8d11dc0fWanlong Gao * with this program; if not, write the Free Software Foundation, Inc.,
21fed9641096e27f79a0f2d9adfe9839dd8d11dc0fWanlong Gao * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
2245a8ba0302fa0632410b2f100f92701651dd7a0fvapier *
23b973f2b91343554586da3c952c63c2369acd879whr * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
24b973f2b91343554586da3c952c63c2369acd879whr * Mountain View, CA  94043, or:
2545a8ba0302fa0632410b2f100f92701651dd7a0fvapier *
2645a8ba0302fa0632410b2f100f92701651dd7a0fvapier * http://www.sgi.com
2745a8ba0302fa0632410b2f100f92701651dd7a0fvapier *
2845a8ba0302fa0632410b2f100f92701651dd7a0fvapier * For further information regarding this notice, see:
2945a8ba0302fa0632410b2f100f92701651dd7a0fvapier *
30b973f2b91343554586da3c952c63c2369acd879whr * http://oss.sgi.com/projects/GenInfo/NoticeExplan/
31b973f2b91343554586da3c952c63c2369acd879whr */
32b973f2b91343554586da3c952c63c2369acd879whr/*
33b973f2b91343554586da3c952c63c2369acd879whr * This module contains code for logging writes to files, and for
34b973f2b91343554586da3c952c63c2369acd879whr * perusing the resultant logfile.  The main intent of all this is
35b973f2b91343554586da3c952c63c2369acd879whr * to provide a 'write history' of a file which can be examined to
36b973f2b91343554586da3c952c63c2369acd879whr * judge the state of a file (ie. whether it is corrupted or not) based
37b973f2b91343554586da3c952c63c2369acd879whr * on the write activity.
38b973f2b91343554586da3c952c63c2369acd879whr *
39b973f2b91343554586da3c952c63c2369acd879whr * The main abstractions available to the user are the wlog_file, and
40b973f2b91343554586da3c952c63c2369acd879whr * the wlog_rec.  A wlog_file is a handle encapsulating a write logfile.
41b973f2b91343554586da3c952c63c2369acd879whr * It is initialized with the wlog_open() function.  This handle is
42b973f2b91343554586da3c952c63c2369acd879whr * then passed to the various wlog_xxx() functions to provide transparent
43b973f2b91343554586da3c952c63c2369acd879whr * access to the write logfile.
44b973f2b91343554586da3c952c63c2369acd879whr *
45b973f2b91343554586da3c952c63c2369acd879whr * The wlog_rec datatype is a structure which contains all the information
46b973f2b91343554586da3c952c63c2369acd879whr * about a file write.  Examples include the file name, offset, length,
47b973f2b91343554586da3c952c63c2369acd879whr * pattern, etc.  In addition there is a bit which is cleared/set based
4845a8ba0302fa0632410b2f100f92701651dd7a0fvapier * on whether or not the write has been confirmed as complete.  This
49b973f2b91343554586da3c952c63c2369acd879whr * allows the write logfile to contain information on writes which have
50b973f2b91343554586da3c952c63c2369acd879whr * been initiated, but not yet completed (as in async io).
51b973f2b91343554586da3c952c63c2369acd879whr *
52b973f2b91343554586da3c952c63c2369acd879whr * There is also a function to scan a write logfile in reverse order.
53b973f2b91343554586da3c952c63c2369acd879whr *
54b973f2b91343554586da3c952c63c2369acd879whr * NOTE:	For target file analysis based on a write logfile, the
55b973f2b91343554586da3c952c63c2369acd879whr * 		assumption is made that the file being written to is
56b973f2b91343554586da3c952c63c2369acd879whr * 		locked from simultaneous access, so that the order of
57b973f2b91343554586da3c952c63c2369acd879whr * 		write completion is predictable.  This is an issue when
58b973f2b91343554586da3c952c63c2369acd879whr * 		more than 1 process is trying to write data to the same
59b973f2b91343554586da3c952c63c2369acd879whr *		target file simultaneously.
60b973f2b91343554586da3c952c63c2369acd879whr *
61b973f2b91343554586da3c952c63c2369acd879whr * The history file created is a collection of variable length records
62b973f2b91343554586da3c952c63c2369acd879whr * described by scruct wlog_rec_disk in write_log.h.  See that module for
63b973f2b91343554586da3c952c63c2369acd879whr * the layout of the data on disk.
64b973f2b91343554586da3c952c63c2369acd879whr */
65b973f2b91343554586da3c952c63c2369acd879whr
66b973f2b91343554586da3c952c63c2369acd879whr#include <stdio.h>
67b973f2b91343554586da3c952c63c2369acd879whr#include <unistd.h>
68b973f2b91343554586da3c952c63c2369acd879whr#include <fcntl.h>
69b973f2b91343554586da3c952c63c2369acd879whr#include <errno.h>
70b973f2b91343554586da3c952c63c2369acd879whr#include <string.h>
71b973f2b91343554586da3c952c63c2369acd879whr#include <sys/param.h>
72b973f2b91343554586da3c952c63c2369acd879whr#include <sys/stat.h>
73b973f2b91343554586da3c952c63c2369acd879whr#include <sys/types.h>
74b973f2b91343554586da3c952c63c2369acd879whr#include "write_log.h"
75b973f2b91343554586da3c952c63c2369acd879whr
76b973f2b91343554586da3c952c63c2369acd879whr#ifndef BSIZE
77e6508f8343333b4fe0696cf354e5f0cd7a2289b6mridge#ifdef DEV_BSIZE
78b973f2b91343554586da3c952c63c2369acd879whr#define BSIZE DEV_BSIZE
79b973f2b91343554586da3c952c63c2369acd879whr#else
80b973f2b91343554586da3c952c63c2369acd879whr#define BSIZE BBSIZE
81b973f2b91343554586da3c952c63c2369acd879whr#endif
82b973f2b91343554586da3c952c63c2369acd879whr#endif
83b973f2b91343554586da3c952c63c2369acd879whr
84b973f2b91343554586da3c952c63c2369acd879whr#ifndef PATH_MAX
85b973f2b91343554586da3c952c63c2369acd879whr#define PATH_MAX          255
86b973f2b91343554586da3c952c63c2369acd879whr/*#define PATH_MAX pathconf("/", _PC_PATH_MAX)*/
87b973f2b91343554586da3c952c63c2369acd879whr#endif
88b973f2b91343554586da3c952c63c2369acd879whr
89354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaochar Wlog_Error_String[256];
90b973f2b91343554586da3c952c63c2369acd879whr
91b973f2b91343554586da3c952c63c2369acd879whr#if __STDC__
92354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaostatic int wlog_rec_pack(struct wlog_rec *wrec, char *buf, int flag);
93354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaostatic int wlog_rec_unpack(struct wlog_rec *wrec, char *buf);
94b973f2b91343554586da3c952c63c2369acd879whr#else
95354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaostatic int wlog_rec_pack();
96354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaostatic int wlog_rec_unpack();
97b973f2b91343554586da3c952c63c2369acd879whr#endif
98b973f2b91343554586da3c952c63c2369acd879whr
99b973f2b91343554586da3c952c63c2369acd879whr/*
100b973f2b91343554586da3c952c63c2369acd879whr * Initialize a write logfile.  wfile is a wlog_file structure that has
101b973f2b91343554586da3c952c63c2369acd879whr * the w_file field filled in.  The rest of the information in the
102b973f2b91343554586da3c952c63c2369acd879whr * structure is initialized by the routine.
103b973f2b91343554586da3c952c63c2369acd879whr *
104b973f2b91343554586da3c952c63c2369acd879whr * The trunc flag is used to indicate whether or not the logfile should
105b973f2b91343554586da3c952c63c2369acd879whr * be truncated if it currently exists.  If it is non-zero, the file will
106b973f2b91343554586da3c952c63c2369acd879whr * be truncated, otherwise it will be appended to.
107b973f2b91343554586da3c952c63c2369acd879whr *
108b973f2b91343554586da3c952c63c2369acd879whr * The mode argument is the [absolute] mode which the file will be
109b973f2b91343554586da3c952c63c2369acd879whr * given if it does not exist.  This mode is not affected by your process
110b973f2b91343554586da3c952c63c2369acd879whr * umask.
111b973f2b91343554586da3c952c63c2369acd879whr */
112b973f2b91343554586da3c952c63c2369acd879whr
11387aa2dc20992208fd7478d14425c1e395a57e0c4Stanislav Kholmanskikhint wlog_open(struct wlog_file *wfile, int trunc, int mode)
114b973f2b91343554586da3c952c63c2369acd879whr{
115354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	int omask, oflags;
116b973f2b91343554586da3c952c63c2369acd879whr
117b973f2b91343554586da3c952c63c2369acd879whr	if (trunc)
118b973f2b91343554586da3c952c63c2369acd879whr		trunc = O_TRUNC;
119b973f2b91343554586da3c952c63c2369acd879whr
120b973f2b91343554586da3c952c63c2369acd879whr	omask = umask(0);
121b973f2b91343554586da3c952c63c2369acd879whr
122b973f2b91343554586da3c952c63c2369acd879whr	/*
123b973f2b91343554586da3c952c63c2369acd879whr	 * Open 1 file descriptor as O_APPEND
124b973f2b91343554586da3c952c63c2369acd879whr	 */
125b973f2b91343554586da3c952c63c2369acd879whr
126b973f2b91343554586da3c952c63c2369acd879whr	oflags = O_WRONLY | O_APPEND | O_CREAT | trunc;
127354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	wfile->w_afd = open(wfile->w_file, oflags, mode);
128b973f2b91343554586da3c952c63c2369acd879whr	umask(omask);
129b973f2b91343554586da3c952c63c2369acd879whr
130b973f2b91343554586da3c952c63c2369acd879whr	if (wfile->w_afd == -1) {
131b973f2b91343554586da3c952c63c2369acd879whr		sprintf(Wlog_Error_String,
132b973f2b91343554586da3c952c63c2369acd879whr			"Could not open write_log - open(%s, %#o, %#o) failed:  %s\n",
1339418108733276af88b5458a866b6cd9a90e9232anstraz			wfile->w_file, oflags, mode, strerror(errno));
134b973f2b91343554586da3c952c63c2369acd879whr		return -1;
135b973f2b91343554586da3c952c63c2369acd879whr	}
136b973f2b91343554586da3c952c63c2369acd879whr
137b973f2b91343554586da3c952c63c2369acd879whr	/*
138b973f2b91343554586da3c952c63c2369acd879whr	 * Open the next fd as a random access descriptor
139b973f2b91343554586da3c952c63c2369acd879whr	 */
140b973f2b91343554586da3c952c63c2369acd879whr
141b973f2b91343554586da3c952c63c2369acd879whr	oflags = O_RDWR;
142e753fd7967c95651b952dd6fe67d2cb56478056esubrata_modak	if ((wfile->w_rfd = open(wfile->w_file, oflags)) == -1) {
143b973f2b91343554586da3c952c63c2369acd879whr		sprintf(Wlog_Error_String,
144b973f2b91343554586da3c952c63c2369acd879whr			"Could not open write log - open(%s, %#o) failed:  %s\n",
1459418108733276af88b5458a866b6cd9a90e9232anstraz			wfile->w_file, oflags, strerror(errno));
146b973f2b91343554586da3c952c63c2369acd879whr		close(wfile->w_afd);
147b973f2b91343554586da3c952c63c2369acd879whr		wfile->w_afd = -1;
148b973f2b91343554586da3c952c63c2369acd879whr		return -1;
149b973f2b91343554586da3c952c63c2369acd879whr	}
15045a8ba0302fa0632410b2f100f92701651dd7a0fvapier
151b973f2b91343554586da3c952c63c2369acd879whr	return 0;
152b973f2b91343554586da3c952c63c2369acd879whr}
153b973f2b91343554586da3c952c63c2369acd879whr
154b973f2b91343554586da3c952c63c2369acd879whr/*
155b973f2b91343554586da3c952c63c2369acd879whr * Release all resources associated with a wlog_file structure allocated
156b973f2b91343554586da3c952c63c2369acd879whr * with the wlog_open() call.
157b973f2b91343554586da3c952c63c2369acd879whr */
158b973f2b91343554586da3c952c63c2369acd879whr
15987aa2dc20992208fd7478d14425c1e395a57e0c4Stanislav Kholmanskikhint wlog_close(struct wlog_file *wfile)
160b973f2b91343554586da3c952c63c2369acd879whr{
161b973f2b91343554586da3c952c63c2369acd879whr	close(wfile->w_afd);
162b973f2b91343554586da3c952c63c2369acd879whr	close(wfile->w_rfd);
163b973f2b91343554586da3c952c63c2369acd879whr	return 0;
164b973f2b91343554586da3c952c63c2369acd879whr}
165b973f2b91343554586da3c952c63c2369acd879whr
166b973f2b91343554586da3c952c63c2369acd879whr/*
167b973f2b91343554586da3c952c63c2369acd879whr * Write a wlog_rec structure to a write logfile.  Offset is used to
168b973f2b91343554586da3c952c63c2369acd879whr * control where the record will be written.  If offset is < 0, the
169b973f2b91343554586da3c952c63c2369acd879whr * record will be appended to the end of the logfile.  Otherwise, the
170b973f2b91343554586da3c952c63c2369acd879whr * record which exists at the indicated offset will be overlayed.  This
171b973f2b91343554586da3c952c63c2369acd879whr * is so that we can record writes which are outstanding (with the w_done
172b973f2b91343554586da3c952c63c2369acd879whr * bit in wrec cleared), but not completed, and then later update the
173b973f2b91343554586da3c952c63c2369acd879whr * logfile when the write request completes (as with async io).  When
17445a8ba0302fa0632410b2f100f92701651dd7a0fvapier * offset is >= 0, only the fixed length portion of the record is
175b973f2b91343554586da3c952c63c2369acd879whr * rewritten.  See text in write_log.h for details on the format of an
176b973f2b91343554586da3c952c63c2369acd879whr * on-disk record.
17745a8ba0302fa0632410b2f100f92701651dd7a0fvapier *
178b973f2b91343554586da3c952c63c2369acd879whr * The return value of the function is the byte offset in the logfile
179b973f2b91343554586da3c952c63c2369acd879whr * where the record begins.
180b973f2b91343554586da3c952c63c2369acd879whr *
181b973f2b91343554586da3c952c63c2369acd879whr * Note:  It is the callers responsibility to make sure that the offset
182b973f2b91343554586da3c952c63c2369acd879whr * parameter 'points' to a valid record location when a record is to be
183b973f2b91343554586da3c952c63c2369acd879whr * overlayed.  This is guarenteed by saving the return value of a previous
184b973f2b91343554586da3c952c63c2369acd879whr * call to wlog_record_write() which wrote the record to be overlayed.
185b973f2b91343554586da3c952c63c2369acd879whr *
186b973f2b91343554586da3c952c63c2369acd879whr * Note2:  The on-disk version of the wlog_rec is MUCH different than
187b973f2b91343554586da3c952c63c2369acd879whr * the user version.  Don't expect to od the logfile and see data formatted
188b973f2b91343554586da3c952c63c2369acd879whr * as it is in the wlog_rec structure.  Considerable data packing takes
189b973f2b91343554586da3c952c63c2369acd879whr * place before the record is written.
190b973f2b91343554586da3c952c63c2369acd879whr */
191b973f2b91343554586da3c952c63c2369acd879whr
19287aa2dc20992208fd7478d14425c1e395a57e0c4Stanislav Kholmanskikhint wlog_record_write(struct wlog_file *wfile, struct wlog_rec *wrec,
19387aa2dc20992208fd7478d14425c1e395a57e0c4Stanislav Kholmanskikh			long offset)
194b973f2b91343554586da3c952c63c2369acd879whr{
195354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	int reclen;
196354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	char wbuf[WLOG_REC_MAX_SIZE + 2];
197b973f2b91343554586da3c952c63c2369acd879whr
198b973f2b91343554586da3c952c63c2369acd879whr	/*
199354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	 * If offset is -1, we append the record at the end of file
200354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	 *
201354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	 * Otherwise, we overlay wrec at the file offset indicated and assume
202354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	 * that the caller passed us the correct offset.  We do not record the
203354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	 * fname in this case.
204b973f2b91343554586da3c952c63c2369acd879whr	 */
20545a8ba0302fa0632410b2f100f92701651dd7a0fvapier
206354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	reclen = wlog_rec_pack(wrec, wbuf, (offset < 0));
207354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
208354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (offset < 0) {
209354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		/*
210354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		 * Since we're writing a complete new record, we must also tack
211354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		 * its length onto the end so that wlog_scan_backward() will work.
212354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		 * Length is asumed to fit into 2 bytes.
213354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		 */
214354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
215354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		wbuf[reclen] = reclen / 256;
216354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		wbuf[reclen + 1] = reclen % 256;
217354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		reclen += 2;
218354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
219354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		if (write(wfile->w_afd, wbuf, reclen) == -1) {
220354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			sprintf(Wlog_Error_String,
221354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				"Could not write log - write(%s, %s, %d) failed:  %s\n",
222354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				wfile->w_file, wbuf, reclen, strerror(errno));
223354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			return -1;
224354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		} else {
225354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			offset = lseek(wfile->w_afd, 0, SEEK_CUR) - reclen;
226354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			if (offset == -1) {
227354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				sprintf(Wlog_Error_String,
228354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao					"Could not reposition file pointer - lseek(%s, 0, SEEK_CUR) failed:  %s\n",
229354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao					wfile->w_file, strerror(errno));
230354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				return -1;
231354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			}
232354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		}
233354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	} else {
234354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		if ((lseek(wfile->w_rfd, offset, SEEK_SET)) == -1) {
235354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			sprintf(Wlog_Error_String,
236354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				"Could not reposition file pointer - lseek(%s, %ld, SEEK_SET) failed:  %s\n",
237354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				wfile->w_file, offset, strerror(errno));
238354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			return -1;
239354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		} else {
240354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			if ((write(wfile->w_rfd, wbuf, reclen)) == -1) {
241354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				sprintf(Wlog_Error_String,
242354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao					"Could not write log - write(%s, %s, %d) failed:  %s\n",
243354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao					wfile->w_file, wbuf, reclen,
244354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao					strerror(errno));
245354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				return -1;
246354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			}
247354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		}
248354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	}
249354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
250354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	return offset;
251b973f2b91343554586da3c952c63c2369acd879whr}
252b973f2b91343554586da3c952c63c2369acd879whr
253b973f2b91343554586da3c952c63c2369acd879whr/*
254b973f2b91343554586da3c952c63c2369acd879whr * Function to scan a logfile in reverse order.  Wfile is a valid
255b973f2b91343554586da3c952c63c2369acd879whr * wlog_file structure initialized by wlog_open().  nrecs is the number
256b973f2b91343554586da3c952c63c2369acd879whr * of records to scan (all records are scanned if nrecs is 0).  func is
257b973f2b91343554586da3c952c63c2369acd879whr * a user-supplied function to call for each record found.  The function
258b973f2b91343554586da3c952c63c2369acd879whr * will be passed a single parameter - a wlog_rec structure .
259b973f2b91343554586da3c952c63c2369acd879whr */
260b973f2b91343554586da3c952c63c2369acd879whr
26187aa2dc20992208fd7478d14425c1e395a57e0c4Stanislav Kholmanskikhint wlog_scan_backward(struct wlog_file *wfile, int nrecs,
26287aa2dc20992208fd7478d14425c1e395a57e0c4Stanislav Kholmanskikh			int (*func)(), long data)
263b973f2b91343554586da3c952c63c2369acd879whr{
264354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	int fd, leftover, nbytes, offset, recnum, reclen, rval;
265354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	char buf[BSIZE * 32], *bufend, *cp, *bufstart;
266354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	char albuf[WLOG_REC_MAX_SIZE];
267354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	struct wlog_rec wrec;
268b973f2b91343554586da3c952c63c2369acd879whr
269b973f2b91343554586da3c952c63c2369acd879whr	fd = wfile->w_rfd;
270b973f2b91343554586da3c952c63c2369acd879whr
271b973f2b91343554586da3c952c63c2369acd879whr	/*
272b973f2b91343554586da3c952c63c2369acd879whr	 * Move to EOF.  offset will always hold the current file offset
273b973f2b91343554586da3c952c63c2369acd879whr	 */
274b973f2b91343554586da3c952c63c2369acd879whr
275354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if ((lseek(fd, 0, SEEK_END)) == -1) {
276354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		sprintf(Wlog_Error_String,
277354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			"Could not reposition file pointer - lseek(%s, 0, SEEK_END) failed:  %s\n",
278354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			wfile->w_file, strerror(errno));
279354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		return -1;
280354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	}
281b973f2b91343554586da3c952c63c2369acd879whr	offset = lseek(fd, 0, SEEK_CUR);
282354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if ((offset == -1)) {
283354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		sprintf(Wlog_Error_String,
284354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			"Could not reposition file pointer - lseek(%s, 0, SEEK_CUR) failed:  %s\n",
285354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			wfile->w_file, strerror(errno));
286354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		return -1;
287354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	}
288b973f2b91343554586da3c952c63c2369acd879whr
289b973f2b91343554586da3c952c63c2369acd879whr	bufend = buf + sizeof(buf);
290b973f2b91343554586da3c952c63c2369acd879whr	bufstart = buf;
291b973f2b91343554586da3c952c63c2369acd879whr
292b973f2b91343554586da3c952c63c2369acd879whr	recnum = 0;
293b973f2b91343554586da3c952c63c2369acd879whr	leftover = 0;
294b973f2b91343554586da3c952c63c2369acd879whr	while ((!nrecs || recnum < nrecs) && offset > 0) {
295b973f2b91343554586da3c952c63c2369acd879whr		/*
296b973f2b91343554586da3c952c63c2369acd879whr		 * Check for beginning of file - if there aren't enough bytes
297b973f2b91343554586da3c952c63c2369acd879whr		 * remaining to fill buf, adjust bufstart.
298b973f2b91343554586da3c952c63c2369acd879whr		 */
299b973f2b91343554586da3c952c63c2369acd879whr
3000ccc8271427b5d80cc67a8164a0876549e7873ebrobbiew		if ((unsigned int)offset + leftover < sizeof(buf)) {
301b973f2b91343554586da3c952c63c2369acd879whr			bufstart = bufend - (offset + leftover);
302b973f2b91343554586da3c952c63c2369acd879whr			offset = 0;
303b973f2b91343554586da3c952c63c2369acd879whr		} else {
304b973f2b91343554586da3c952c63c2369acd879whr			offset -= sizeof(buf) - leftover;
305b973f2b91343554586da3c952c63c2369acd879whr		}
306b973f2b91343554586da3c952c63c2369acd879whr
30745a8ba0302fa0632410b2f100f92701651dd7a0fvapier		/*
308b973f2b91343554586da3c952c63c2369acd879whr		 * Move to the proper file offset, and read into buf
309b973f2b91343554586da3c952c63c2369acd879whr		 */
310354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		if ((lseek(fd, offset, SEEK_SET)) == -1) {
311354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			sprintf(Wlog_Error_String,
312354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				"Could not reposition file pointer - lseek(%s, %d, SEEK_SET) failed:  %s\n",
313354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				wfile->w_file, offset, strerror(errno));
314354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			return -1;
315354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		}
316b973f2b91343554586da3c952c63c2369acd879whr
317b973f2b91343554586da3c952c63c2369acd879whr		nbytes = read(fd, bufstart, bufend - bufstart - leftover);
318b973f2b91343554586da3c952c63c2369acd879whr
319b973f2b91343554586da3c952c63c2369acd879whr		if (nbytes == -1) {
320b973f2b91343554586da3c952c63c2369acd879whr			sprintf(Wlog_Error_String,
321f3a83d59cce260ab513313b2c43c41fc16983959robbiew				"Could not read history file at offset %d - read(%d, %p, %d) failed:  %s\n",
32215226cdbc46b1a13023484bd304b13aa47d42b87robbiew				offset, fd, bufstart,
323354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				(int)(bufend - bufstart - leftover),
324354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				strerror(errno));
325b973f2b91343554586da3c952c63c2369acd879whr			return -1;
326b973f2b91343554586da3c952c63c2369acd879whr		}
327b973f2b91343554586da3c952c63c2369acd879whr
328b973f2b91343554586da3c952c63c2369acd879whr		cp = bufend;
329b973f2b91343554586da3c952c63c2369acd879whr		leftover = 0;
330b973f2b91343554586da3c952c63c2369acd879whr
331b973f2b91343554586da3c952c63c2369acd879whr		while (cp >= bufstart) {
332b973f2b91343554586da3c952c63c2369acd879whr
333b973f2b91343554586da3c952c63c2369acd879whr			/*
334b973f2b91343554586da3c952c63c2369acd879whr			 * If cp-bufstart is not large enough to hold a piece
335b973f2b91343554586da3c952c63c2369acd879whr			 * of record length information, copy remainder to end
336b973f2b91343554586da3c952c63c2369acd879whr			 * of buf and continue reading the file.
337b973f2b91343554586da3c952c63c2369acd879whr			 */
338b973f2b91343554586da3c952c63c2369acd879whr
339b973f2b91343554586da3c952c63c2369acd879whr			if (cp - bufstart < 2) {
340b973f2b91343554586da3c952c63c2369acd879whr				leftover = cp - bufstart;
341b973f2b91343554586da3c952c63c2369acd879whr				memcpy(bufend - leftover, bufstart, leftover);
342b973f2b91343554586da3c952c63c2369acd879whr				break;
343b973f2b91343554586da3c952c63c2369acd879whr			}
344b973f2b91343554586da3c952c63c2369acd879whr
345b973f2b91343554586da3c952c63c2369acd879whr			/*
346b973f2b91343554586da3c952c63c2369acd879whr			 * Extract the record length.  We must do it this way
347b973f2b91343554586da3c952c63c2369acd879whr			 * instead of casting cp to an int because cp might
348b973f2b91343554586da3c952c63c2369acd879whr			 * not be word aligned.
349b973f2b91343554586da3c952c63c2369acd879whr			 */
350b973f2b91343554586da3c952c63c2369acd879whr
351354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			reclen = (*(cp - 2) * 256) + *(cp - 1);
352b973f2b91343554586da3c952c63c2369acd879whr
353b973f2b91343554586da3c952c63c2369acd879whr			/*
354b973f2b91343554586da3c952c63c2369acd879whr			 * If cp-bufstart isn't large enough to hold a
355b973f2b91343554586da3c952c63c2369acd879whr			 * complete record, plus the length information, copy
356b973f2b91343554586da3c952c63c2369acd879whr			 * the leftover bytes to the end of buf and continue
357b973f2b91343554586da3c952c63c2369acd879whr			 * reading.
358b973f2b91343554586da3c952c63c2369acd879whr			 */
359b973f2b91343554586da3c952c63c2369acd879whr
360b973f2b91343554586da3c952c63c2369acd879whr			if (cp - bufstart < reclen + 2) {
361b973f2b91343554586da3c952c63c2369acd879whr				leftover = cp - bufstart;
362b973f2b91343554586da3c952c63c2369acd879whr				memcpy(bufend - leftover, bufstart, leftover);
363b973f2b91343554586da3c952c63c2369acd879whr				break;
364b973f2b91343554586da3c952c63c2369acd879whr			}
365b973f2b91343554586da3c952c63c2369acd879whr
366b973f2b91343554586da3c952c63c2369acd879whr			/*
367b973f2b91343554586da3c952c63c2369acd879whr			 * Adjust cp to point at the start of the record.
368b973f2b91343554586da3c952c63c2369acd879whr			 * Copy the record into wbuf so that it is word
369b973f2b91343554586da3c952c63c2369acd879whr			 * aligned and pass the record to the user supplied
370b973f2b91343554586da3c952c63c2369acd879whr			 * function.
371b973f2b91343554586da3c952c63c2369acd879whr			 */
372b973f2b91343554586da3c952c63c2369acd879whr
373b973f2b91343554586da3c952c63c2369acd879whr			cp -= reclen + 2;
374b973f2b91343554586da3c952c63c2369acd879whr			memcpy(albuf, cp, reclen);
375b973f2b91343554586da3c952c63c2369acd879whr
376b973f2b91343554586da3c952c63c2369acd879whr			wlog_rec_unpack(&wrec, albuf);
377b973f2b91343554586da3c952c63c2369acd879whr
378b973f2b91343554586da3c952c63c2369acd879whr			/*
379b973f2b91343554586da3c952c63c2369acd879whr			 * Call the user supplied function -
380b973f2b91343554586da3c952c63c2369acd879whr			 * stop if instructed to.
381b973f2b91343554586da3c952c63c2369acd879whr			 */
382b973f2b91343554586da3c952c63c2369acd879whr
383354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			if ((rval = (*func) (&wrec, data)) == WLOG_STOP_SCAN) {
384b973f2b91343554586da3c952c63c2369acd879whr				break;
385b973f2b91343554586da3c952c63c2369acd879whr			}
386b973f2b91343554586da3c952c63c2369acd879whr
387b973f2b91343554586da3c952c63c2369acd879whr			recnum++;
388b973f2b91343554586da3c952c63c2369acd879whr
389b973f2b91343554586da3c952c63c2369acd879whr			if (nrecs && recnum >= nrecs)
390b973f2b91343554586da3c952c63c2369acd879whr				break;
391b973f2b91343554586da3c952c63c2369acd879whr		}
392b973f2b91343554586da3c952c63c2369acd879whr	}
393b973f2b91343554586da3c952c63c2369acd879whr
394b973f2b91343554586da3c952c63c2369acd879whr	return 0;
395b973f2b91343554586da3c952c63c2369acd879whr}
396b973f2b91343554586da3c952c63c2369acd879whr
397b973f2b91343554586da3c952c63c2369acd879whr/*
398b973f2b91343554586da3c952c63c2369acd879whr * The following 2 routines are used to pack and unpack the user
399b973f2b91343554586da3c952c63c2369acd879whr * visible wlog_rec structure to/from a character buffer which is
400b973f2b91343554586da3c952c63c2369acd879whr * stored or read from the write logfile.  Any changes to either of
401b973f2b91343554586da3c952c63c2369acd879whr * these routines must be reflected in the other.
402b973f2b91343554586da3c952c63c2369acd879whr */
403b973f2b91343554586da3c952c63c2369acd879whr
40487aa2dc20992208fd7478d14425c1e395a57e0c4Stanislav Kholmanskikhstatic int wlog_rec_pack(struct wlog_rec *wrec, char *buf, int flag)
405b973f2b91343554586da3c952c63c2369acd879whr{
406354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	char *file, *host, *pattern;
407354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	struct wlog_rec_disk *wrecd;
408b973f2b91343554586da3c952c63c2369acd879whr
409b973f2b91343554586da3c952c63c2369acd879whr	wrecd = (struct wlog_rec_disk *)buf;
410b973f2b91343554586da3c952c63c2369acd879whr
411354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	wrecd->w_pid = (uint) wrec->w_pid;
412354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	wrecd->w_offset = (uint) wrec->w_offset;
413354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	wrecd->w_nbytes = (uint) wrec->w_nbytes;
414354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	wrecd->w_oflags = (uint) wrec->w_oflags;
415354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	wrecd->w_done = (uint) wrec->w_done;
416354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	wrecd->w_async = (uint) wrec->w_async;
417b973f2b91343554586da3c952c63c2369acd879whr
418354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	wrecd->w_pathlen = (wrec->w_pathlen > 0) ? (uint) wrec->w_pathlen : 0;
419354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	wrecd->w_hostlen = (wrec->w_hostlen > 0) ? (uint) wrec->w_hostlen : 0;
420354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	wrecd->w_patternlen =
421354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	    (wrec->w_patternlen > 0) ? (uint) wrec->w_patternlen : 0;
422b973f2b91343554586da3c952c63c2369acd879whr
423b973f2b91343554586da3c952c63c2369acd879whr	/*
424b973f2b91343554586da3c952c63c2369acd879whr	 * If flag is true, we should also pack the variable length parts
425b973f2b91343554586da3c952c63c2369acd879whr	 * of the wlog_rec.  By default, we only pack the fixed length
426b973f2b91343554586da3c952c63c2369acd879whr	 * parts.
427b973f2b91343554586da3c952c63c2369acd879whr	 */
428b973f2b91343554586da3c952c63c2369acd879whr
429b973f2b91343554586da3c952c63c2369acd879whr	if (flag) {
430b973f2b91343554586da3c952c63c2369acd879whr		file = buf + sizeof(struct wlog_rec_disk);
431b973f2b91343554586da3c952c63c2369acd879whr		host = file + wrecd->w_pathlen;
432b973f2b91343554586da3c952c63c2369acd879whr		pattern = host + wrecd->w_hostlen;
43345a8ba0302fa0632410b2f100f92701651dd7a0fvapier
434b973f2b91343554586da3c952c63c2369acd879whr		if (wrecd->w_pathlen > 0)
435b973f2b91343554586da3c952c63c2369acd879whr			memcpy(file, wrec->w_path, wrecd->w_pathlen);
43645a8ba0302fa0632410b2f100f92701651dd7a0fvapier
437b973f2b91343554586da3c952c63c2369acd879whr		if (wrecd->w_hostlen > 0)
438b973f2b91343554586da3c952c63c2369acd879whr			memcpy(host, wrec->w_host, wrecd->w_hostlen);
43945a8ba0302fa0632410b2f100f92701651dd7a0fvapier
440b973f2b91343554586da3c952c63c2369acd879whr		if (wrecd->w_patternlen > 0)
441b973f2b91343554586da3c952c63c2369acd879whr			memcpy(pattern, wrec->w_pattern, wrecd->w_patternlen);
442b973f2b91343554586da3c952c63c2369acd879whr
443b973f2b91343554586da3c952c63c2369acd879whr		return (sizeof(struct wlog_rec_disk) +
444354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			wrecd->w_pathlen + wrecd->w_hostlen +
445354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			wrecd->w_patternlen);
446b973f2b91343554586da3c952c63c2369acd879whr	} else {
447b973f2b91343554586da3c952c63c2369acd879whr		return sizeof(struct wlog_rec_disk);
448b973f2b91343554586da3c952c63c2369acd879whr	}
449b973f2b91343554586da3c952c63c2369acd879whr}
450b973f2b91343554586da3c952c63c2369acd879whr
45187aa2dc20992208fd7478d14425c1e395a57e0c4Stanislav Kholmanskikhstatic int wlog_rec_unpack(struct wlog_rec *wrec, char *buf)
452b973f2b91343554586da3c952c63c2369acd879whr{
453354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	char *file, *host, *pattern;
454354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	struct wlog_rec_disk *wrecd;
455b973f2b91343554586da3c952c63c2369acd879whr
45632cc0acd99e36836b13056c6d0e3e62a115678f3vapier	memset((char *)wrec, 0x00, sizeof(struct wlog_rec));
457b973f2b91343554586da3c952c63c2369acd879whr	wrecd = (struct wlog_rec_disk *)buf;
458b973f2b91343554586da3c952c63c2369acd879whr
459b973f2b91343554586da3c952c63c2369acd879whr	wrec->w_pid = wrecd->w_pid;
460b973f2b91343554586da3c952c63c2369acd879whr	wrec->w_offset = wrecd->w_offset;
461b973f2b91343554586da3c952c63c2369acd879whr	wrec->w_nbytes = wrecd->w_nbytes;
462b973f2b91343554586da3c952c63c2369acd879whr	wrec->w_oflags = wrecd->w_oflags;
463b973f2b91343554586da3c952c63c2369acd879whr	wrec->w_hostlen = wrecd->w_hostlen;
464b973f2b91343554586da3c952c63c2369acd879whr	wrec->w_pathlen = wrecd->w_pathlen;
465b973f2b91343554586da3c952c63c2369acd879whr	wrec->w_patternlen = wrecd->w_patternlen;
466b973f2b91343554586da3c952c63c2369acd879whr	wrec->w_done = wrecd->w_done;
467b973f2b91343554586da3c952c63c2369acd879whr	wrec->w_async = wrecd->w_async;
468b973f2b91343554586da3c952c63c2369acd879whr
469b973f2b91343554586da3c952c63c2369acd879whr	if (wrec->w_pathlen > 0) {
470b973f2b91343554586da3c952c63c2369acd879whr		file = buf + sizeof(struct wlog_rec_disk);
471b973f2b91343554586da3c952c63c2369acd879whr		memcpy(wrec->w_path, file, wrec->w_pathlen);
472b973f2b91343554586da3c952c63c2369acd879whr	}
473b973f2b91343554586da3c952c63c2369acd879whr
474b973f2b91343554586da3c952c63c2369acd879whr	if (wrec->w_hostlen > 0) {
475b973f2b91343554586da3c952c63c2369acd879whr		host = buf + sizeof(struct wlog_rec_disk) + wrec->w_pathlen;
476b973f2b91343554586da3c952c63c2369acd879whr		memcpy(wrec->w_host, host, wrec->w_hostlen);
477b973f2b91343554586da3c952c63c2369acd879whr	}
478b973f2b91343554586da3c952c63c2369acd879whr
479b973f2b91343554586da3c952c63c2369acd879whr	if (wrec->w_patternlen > 0) {
480b973f2b91343554586da3c952c63c2369acd879whr		pattern = buf + sizeof(struct wlog_rec_disk) +
481354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		    wrec->w_pathlen + wrec->w_hostlen;
482b973f2b91343554586da3c952c63c2369acd879whr		memcpy(wrec->w_pattern, pattern, wrec->w_patternlen);
483b973f2b91343554586da3c952c63c2369acd879whr	}
484b973f2b91343554586da3c952c63c2369acd879whr
485b973f2b91343554586da3c952c63c2369acd879whr	return 0;
486ec6edca7aa42b6affd989ef91b5897f96795e40fChris Dearman}
487