summaryrefslogtreecommitdiff
path: root/ltp_framework/lib/write_log.c
diff options
context:
space:
mode:
Diffstat (limited to 'ltp_framework/lib/write_log.c')
-rw-r--r--ltp_framework/lib/write_log.c503
1 files changed, 503 insertions, 0 deletions
diff --git a/ltp_framework/lib/write_log.c b/ltp_framework/lib/write_log.c
new file mode 100644
index 0000000..ef560e7
--- /dev/null
+++ b/ltp_framework/lib/write_log.c
@@ -0,0 +1,503 @@
+/*
+ * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA 94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/NoticeExplan/
+ */
+/*
+ * This module contains code for logging writes to files, and for
+ * perusing the resultant logfile. The main intent of all this is
+ * to provide a 'write history' of a file which can be examined to
+ * judge the state of a file (ie. whether it is corrupted or not) based
+ * on the write activity.
+ *
+ * The main abstractions available to the user are the wlog_file, and
+ * the wlog_rec. A wlog_file is a handle encapsulating a write logfile.
+ * It is initialized with the wlog_open() function. This handle is
+ * then passed to the various wlog_xxx() functions to provide transparent
+ * access to the write logfile.
+ *
+ * The wlog_rec datatype is a structure which contains all the information
+ * about a file write. Examples include the file name, offset, length,
+ * pattern, etc. In addition there is a bit which is cleared/set based
+ * on whether or not the write has been confirmed as complete. This
+ * allows the write logfile to contain information on writes which have
+ * been initiated, but not yet completed (as in async io).
+ *
+ * There is also a function to scan a write logfile in reverse order.
+ *
+ * NOTE: For target file analysis based on a write logfile, the
+ * assumption is made that the file being written to is
+ * locked from simultaneous access, so that the order of
+ * write completion is predictable. This is an issue when
+ * more than 1 process is trying to write data to the same
+ * target file simultaneously.
+ *
+ * The history file created is a collection of variable length records
+ * described by scruct wlog_rec_disk in write_log.h. See that module for
+ * the layout of the data on disk.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include "write_log.h"
+
+#ifndef BSIZE
+#ifdef DEV_BSIZE
+#define BSIZE DEV_BSIZE
+#else
+#define BSIZE BBSIZE
+#endif
+#endif
+
+#ifndef PATH_MAX
+#define PATH_MAX 255
+/*#define PATH_MAX pathconf("/", _PC_PATH_MAX)*/
+#endif
+
+char Wlog_Error_String[256];
+
+#if __STDC__
+static int wlog_rec_pack(struct wlog_rec *wrec, char *buf, int flag);
+static int wlog_rec_unpack(struct wlog_rec *wrec, char *buf);
+#else
+static int wlog_rec_pack();
+static int wlog_rec_unpack();
+#endif
+
+/*
+ * Initialize a write logfile. wfile is a wlog_file structure that has
+ * the w_file field filled in. The rest of the information in the
+ * structure is initialized by the routine.
+ *
+ * The trunc flag is used to indicate whether or not the logfile should
+ * be truncated if it currently exists. If it is non-zero, the file will
+ * be truncated, otherwise it will be appended to.
+ *
+ * The mode argument is the [absolute] mode which the file will be
+ * given if it does not exist. This mode is not affected by your process
+ * umask.
+ */
+
+int
+wlog_open(wfile, trunc, mode)
+struct wlog_file *wfile;
+int trunc;
+int mode;
+{
+ int omask, oflags;
+
+ if (trunc)
+ trunc = O_TRUNC;
+
+ omask = umask(0);
+
+ /*
+ * Open 1 file descriptor as O_APPEND
+ */
+
+ oflags = O_WRONLY | O_APPEND | O_CREAT | trunc;
+ wfile->w_afd =
+ open(wfile->w_file, oflags, mode);
+ umask(omask);
+
+ if (wfile->w_afd == -1) {
+ sprintf(Wlog_Error_String,
+ "Could not open write_log - open(%s, %#o, %#o) failed: %s\n",
+ wfile->w_file, oflags, mode, strerror(errno));
+ return -1;
+ }
+
+ /*
+ * Open the next fd as a random access descriptor
+ */
+
+ oflags = O_RDWR;
+ if ((wfile->w_rfd = open(wfile->w_file, oflags)) == -1) {
+ sprintf(Wlog_Error_String,
+ "Could not open write log - open(%s, %#o) failed: %s\n",
+ wfile->w_file, oflags, strerror(errno));
+ close(wfile->w_afd);
+ wfile->w_afd = -1;
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Release all resources associated with a wlog_file structure allocated
+ * with the wlog_open() call.
+ */
+
+int
+wlog_close(wfile)
+struct wlog_file *wfile;
+{
+ close(wfile->w_afd);
+ close(wfile->w_rfd);
+ return 0;
+}
+
+/*
+ * Write a wlog_rec structure to a write logfile. Offset is used to
+ * control where the record will be written. If offset is < 0, the
+ * record will be appended to the end of the logfile. Otherwise, the
+ * record which exists at the indicated offset will be overlayed. This
+ * is so that we can record writes which are outstanding (with the w_done
+ * bit in wrec cleared), but not completed, and then later update the
+ * logfile when the write request completes (as with async io). When
+ * offset is >= 0, only the fixed length portion of the record is
+ * rewritten. See text in write_log.h for details on the format of an
+ * on-disk record.
+ *
+ * The return value of the function is the byte offset in the logfile
+ * where the record begins.
+ *
+ * Note: It is the callers responsibility to make sure that the offset
+ * parameter 'points' to a valid record location when a record is to be
+ * overlayed. This is guarenteed by saving the return value of a previous
+ * call to wlog_record_write() which wrote the record to be overlayed.
+ *
+ * Note2: The on-disk version of the wlog_rec is MUCH different than
+ * the user version. Don't expect to od the logfile and see data formatted
+ * as it is in the wlog_rec structure. Considerable data packing takes
+ * place before the record is written.
+ */
+
+int
+wlog_record_write(wfile, wrec, offset)
+struct wlog_file *wfile;
+struct wlog_rec *wrec;
+long offset;
+{
+ int reclen;
+ char wbuf[WLOG_REC_MAX_SIZE + 2];
+
+ /*
+ * If offset is -1, we append the record at the end of file
+ *
+ * Otherwise, we overlay wrec at the file offset indicated and assume
+ * that the caller passed us the correct offset. We do not record the
+ * fname in this case.
+ */
+
+ reclen = wlog_rec_pack(wrec, wbuf, (offset < 0));
+
+ if (offset < 0) {
+ /*
+ * Since we're writing a complete new record, we must also tack
+ * its length onto the end so that wlog_scan_backward() will work.
+ * Length is asumed to fit into 2 bytes.
+ */
+
+ wbuf[reclen] = reclen / 256;
+ wbuf[reclen+1] = reclen % 256;
+ reclen += 2;
+
+ if (write(wfile->w_afd, wbuf, reclen) == -1) {
+ sprintf(Wlog_Error_String,
+ "Could not write log - write(%s, %s, %d) failed: %s\n",
+ wfile->w_file, wbuf, reclen, strerror(errno));
+ return -1;
+ } else {
+ offset = lseek(wfile->w_afd, 0, SEEK_CUR) - reclen;
+ if (offset == -1) {
+ sprintf(Wlog_Error_String,
+ "Could not reposition file pointer - lseek(%s, 0, SEEK_CUR) failed: %s\n",
+ wfile->w_file, strerror(errno));
+ return -1;
+ }
+ }
+ } else {
+ if ((lseek(wfile->w_rfd, offset, SEEK_SET)) == -1) {
+ sprintf(Wlog_Error_String,
+ "Could not reposition file pointer - lseek(%s, %ld, SEEK_SET) failed: %s\n",
+ wfile->w_file, offset, strerror(errno));
+ return -1;
+ } else {
+ if ((write(wfile->w_rfd, wbuf, reclen)) == -1) {
+ sprintf(Wlog_Error_String,
+ "Could not write log - write(%s, %s, %d) failed: %s\n",
+ wfile->w_file, wbuf, reclen, strerror(errno));
+ return -1;
+ }
+ }
+ }
+
+ return offset;
+}
+
+/*
+ * Function to scan a logfile in reverse order. Wfile is a valid
+ * wlog_file structure initialized by wlog_open(). nrecs is the number
+ * of records to scan (all records are scanned if nrecs is 0). func is
+ * a user-supplied function to call for each record found. The function
+ * will be passed a single parameter - a wlog_rec structure .
+ */
+
+int
+wlog_scan_backward(wfile, nrecs, func, data)
+struct wlog_file *wfile;
+int nrecs;
+int (*func)();
+long data;
+{
+ int fd, leftover, nbytes, offset, recnum, reclen, rval;
+ char buf[BSIZE*32], *bufend, *cp, *bufstart;
+ char albuf[WLOG_REC_MAX_SIZE];
+ struct wlog_rec wrec;
+
+ fd = wfile->w_rfd;
+
+ /*
+ * Move to EOF. offset will always hold the current file offset
+ */
+
+ if ((lseek(fd, 0, SEEK_END)) == -1) {
+ sprintf(Wlog_Error_String,
+ "Could not reposition file pointer - lseek(%s, 0, SEEK_END) failed: %s\n",
+ wfile->w_file, strerror(errno));
+ return -1;
+ }
+ offset = lseek(fd, 0, SEEK_CUR);
+ if ((offset == -1)) {
+ sprintf(Wlog_Error_String,
+ "Could not reposition file pointer - lseek(%s, 0, SEEK_CUR) failed: %s\n",
+ wfile->w_file, strerror(errno));
+ return -1;
+ }
+
+ bufend = buf + sizeof(buf);
+ bufstart = buf;
+
+ recnum = 0;
+ leftover = 0;
+ while ((!nrecs || recnum < nrecs) && offset > 0) {
+ /*
+ * Check for beginning of file - if there aren't enough bytes
+ * remaining to fill buf, adjust bufstart.
+ */
+
+ if ((unsigned int)offset + leftover < sizeof(buf)) {
+ bufstart = bufend - (offset + leftover);
+ offset = 0;
+ } else {
+ offset -= sizeof(buf) - leftover;
+ }
+
+ /*
+ * Move to the proper file offset, and read into buf
+ */
+ if ((lseek(fd, offset, SEEK_SET)) ==-1) {
+ sprintf(Wlog_Error_String,
+ "Could not reposition file pointer - lseek(%s, %d, SEEK_SET) failed: %s\n",
+ wfile->w_file, offset, strerror(errno));
+ return -1;
+ }
+
+ nbytes = read(fd, bufstart, bufend - bufstart - leftover);
+
+ if (nbytes == -1) {
+ sprintf(Wlog_Error_String,
+ "Could not read history file at offset %d - read(%d, %p, %d) failed: %s\n",
+ offset, fd, bufstart,
+ (int)(bufend - bufstart - leftover), strerror(errno));
+ return -1;
+ }
+
+ cp = bufend;
+ leftover = 0;
+
+ while (cp >= bufstart) {
+
+ /*
+ * If cp-bufstart is not large enough to hold a piece
+ * of record length information, copy remainder to end
+ * of buf and continue reading the file.
+ */
+
+ if (cp - bufstart < 2) {
+ leftover = cp - bufstart;
+ memcpy(bufend - leftover, bufstart, leftover);
+ break;
+ }
+
+ /*
+ * Extract the record length. We must do it this way
+ * instead of casting cp to an int because cp might
+ * not be word aligned.
+ */
+
+ reclen = (*(cp-2) * 256) + *(cp -1);
+
+ /*
+ * If cp-bufstart isn't large enough to hold a
+ * complete record, plus the length information, copy
+ * the leftover bytes to the end of buf and continue
+ * reading.
+ */
+
+ if (cp - bufstart < reclen + 2) {
+ leftover = cp - bufstart;
+ memcpy(bufend - leftover, bufstart, leftover);
+ break;
+ }
+
+ /*
+ * Adjust cp to point at the start of the record.
+ * Copy the record into wbuf so that it is word
+ * aligned and pass the record to the user supplied
+ * function.
+ */
+
+ cp -= reclen + 2;
+ memcpy(albuf, cp, reclen);
+
+ wlog_rec_unpack(&wrec, albuf);
+
+ /*
+ * Call the user supplied function -
+ * stop if instructed to.
+ */
+
+ if ((rval = (*func)(&wrec, data)) == WLOG_STOP_SCAN) {
+ break;
+ }
+
+ recnum++;
+
+ if (nrecs && recnum >= nrecs)
+ break;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * The following 2 routines are used to pack and unpack the user
+ * visible wlog_rec structure to/from a character buffer which is
+ * stored or read from the write logfile. Any changes to either of
+ * these routines must be reflected in the other.
+ */
+
+static int
+wlog_rec_pack(wrec, buf, flag)
+struct wlog_rec *wrec;
+char *buf;
+int flag;
+{
+ char *file, *host, *pattern;
+ struct wlog_rec_disk *wrecd;
+
+ wrecd = (struct wlog_rec_disk *)buf;
+
+ wrecd->w_pid = (uint)wrec->w_pid;
+ wrecd->w_offset = (uint)wrec->w_offset;
+ wrecd->w_nbytes = (uint)wrec->w_nbytes;
+ wrecd->w_oflags = (uint)wrec->w_oflags;
+ wrecd->w_done = (uint)wrec->w_done;
+ wrecd->w_async = (uint)wrec->w_async;
+
+ wrecd->w_pathlen = (wrec->w_pathlen > 0) ? (uint)wrec->w_pathlen : 0;
+ wrecd->w_hostlen = (wrec->w_hostlen > 0) ? (uint)wrec->w_hostlen : 0;
+ wrecd->w_patternlen = (wrec->w_patternlen > 0) ? (uint)wrec->w_patternlen : 0;
+
+ /*
+ * If flag is true, we should also pack the variable length parts
+ * of the wlog_rec. By default, we only pack the fixed length
+ * parts.
+ */
+
+ if (flag) {
+ file = buf + sizeof(struct wlog_rec_disk);
+ host = file + wrecd->w_pathlen;
+ pattern = host + wrecd->w_hostlen;
+
+ if (wrecd->w_pathlen > 0)
+ memcpy(file, wrec->w_path, wrecd->w_pathlen);
+
+ if (wrecd->w_hostlen > 0)
+ memcpy(host, wrec->w_host, wrecd->w_hostlen);
+
+ if (wrecd->w_patternlen > 0)
+ memcpy(pattern, wrec->w_pattern, wrecd->w_patternlen);
+
+ return (sizeof(struct wlog_rec_disk) +
+ wrecd->w_pathlen + wrecd->w_hostlen + wrecd->w_patternlen);
+ } else {
+ return sizeof(struct wlog_rec_disk);
+ }
+}
+
+static int
+wlog_rec_unpack(wrec, buf)
+struct wlog_rec *wrec;
+char *buf;
+{
+ char *file, *host, *pattern;
+ struct wlog_rec_disk *wrecd;
+
+ memset((char *)wrec, 0x00, sizeof(struct wlog_rec));
+ wrecd = (struct wlog_rec_disk *)buf;
+
+ wrec->w_pid = wrecd->w_pid;
+ wrec->w_offset = wrecd->w_offset;
+ wrec->w_nbytes = wrecd->w_nbytes;
+ wrec->w_oflags = wrecd->w_oflags;
+ wrec->w_hostlen = wrecd->w_hostlen;
+ wrec->w_pathlen = wrecd->w_pathlen;
+ wrec->w_patternlen = wrecd->w_patternlen;
+ wrec->w_done = wrecd->w_done;
+ wrec->w_async = wrecd->w_async;
+
+ if (wrec->w_pathlen > 0) {
+ file = buf + sizeof(struct wlog_rec_disk);
+ memcpy(wrec->w_path, file, wrec->w_pathlen);
+ }
+
+ if (wrec->w_hostlen > 0) {
+ host = buf + sizeof(struct wlog_rec_disk) + wrec->w_pathlen;
+ memcpy(wrec->w_host, host, wrec->w_hostlen);
+ }
+
+ if (wrec->w_patternlen > 0) {
+ pattern = buf + sizeof(struct wlog_rec_disk) +
+ wrec->w_pathlen + wrec->w_hostlen;
+ memcpy(wrec->w_pattern, pattern, wrec->w_patternlen);
+ }
+
+ return 0;
+} \ No newline at end of file