summaryrefslogtreecommitdiffstats
path: root/usr.bin/lastcomm/readrec.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.bin/lastcomm/readrec.c')
-rw-r--r--usr.bin/lastcomm/readrec.c231
1 files changed, 231 insertions, 0 deletions
diff --git a/usr.bin/lastcomm/readrec.c b/usr.bin/lastcomm/readrec.c
new file mode 100644
index 0000000..4883b2a
--- /dev/null
+++ b/usr.bin/lastcomm/readrec.c
@@ -0,0 +1,231 @@
+/*-
+ * Copyright (c) 2007 Diomidis Spinellis
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/acct.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int readrec_forward(FILE *f, struct acctv2 *av2);
+int readrec_backward(FILE *f, struct acctv2 *av2);
+
+/*
+ * Reverse offsetof: return the offset of field f
+ * from the end of the structure s.
+ */
+#define roffsetof(s, f) (sizeof(s) - offsetof(s, f))
+
+/*
+ * Read exactly one record of size size from stream f into ptr.
+ * Failure to read the complete record is considered a file format error,
+ * and will set errno to EFTYPE.
+ * Return 0 on success, EOF on end of file or error.
+ */
+static int
+fread_record(void *ptr, size_t size, FILE *f)
+{
+ size_t rv;
+
+ if ((rv = fread(ptr, 1, size, f)) == size)
+ return (0);
+ else if (ferror(f) || rv == 0)
+ return (EOF);
+ else {
+ /* Short read. */
+ errno = EFTYPE;
+ return (EOF);
+ }
+}
+
+/*
+ * Return the value of a comp_t field.
+ */
+static float
+decode_comp(comp_t v)
+{
+ int result, exp;
+
+ result = v & 017777;
+ for (exp = v >> 13; exp; exp--)
+ result <<= 3;
+ return ((double)result / AHZV1);
+}
+
+/*
+ * Read a v1 accounting record stored at the current
+ * position of stream f.
+ * Convert the data to the current record format.
+ * Return EOF on error or end-of-file.
+ */
+static int
+readrec_v1(FILE *f, struct acctv2 *av2)
+{
+ struct acctv1 av1;
+ int rv;
+
+ if ((rv = fread_record(&av1, sizeof(av1), f)) == EOF)
+ return (EOF);
+ av2->ac_zero = 0;
+ av2->ac_version = 2;
+ av2->ac_len = av2->ac_len2 = sizeof(*av2);
+ memcpy(av2->ac_comm, av1.ac_comm, AC_COMM_LEN);
+ av2->ac_utime = decode_comp(av1.ac_utime) * 1000000;
+ av2->ac_stime = decode_comp(av1.ac_stime) * 1000000;
+ av2->ac_etime = decode_comp(av1.ac_etime) * 1000000;
+ av2->ac_btime = av1.ac_btime;
+ av2->ac_uid = av1.ac_uid;
+ av2->ac_gid = av1.ac_gid;
+ av2->ac_mem = av1.ac_mem;
+ av2->ac_io = decode_comp(av1.ac_io);
+ av2->ac_tty = av1.ac_tty;
+ av2->ac_flagx = av1.ac_flag | ANVER;
+ return (0);
+}
+
+/*
+ * Read an v2 accounting record stored at the current
+ * position of stream f.
+ * Return EOF on error or end-of-file.
+ */
+static int
+readrec_v2(FILE *f, struct acctv2 *av2)
+{
+ return (fread_record(av2, sizeof(*av2), f));
+}
+
+/*
+ * Read a new-style (post-v1) accounting record stored at
+ * the current position of stream f.
+ * Convert the data to the current record format.
+ * Return EOF on error or end-of-file.
+ */
+static int
+readrec_vx(FILE *f, struct acctv2 *av2)
+{
+ uint8_t magic, version;
+
+ if (fread_record(&magic, sizeof(magic), f) == EOF ||
+ fread_record(&version, sizeof(version), f) == EOF ||
+ ungetc(version, f) == EOF ||
+ ungetc(magic, f) == EOF)
+ return (EOF);
+ switch (version) {
+ case 2:
+ return (readrec_v2(f, av2));
+
+ /* Add handling for more versions here. */
+
+ default:
+ errno = EFTYPE;
+ return (EOF);
+ }
+}
+
+/*
+ * Read an accounting record stored at the current
+ * position of stream f.
+ * Old-format records are converted to the current record
+ * format.
+ * Return the number of records read (1 or 0 at the end-of-file),
+ * or EOF on error.
+ */
+int
+readrec_forward(FILE *f, struct acctv2 *av2)
+{
+ int magic, rv;
+
+ if ((magic = getc(f)) == EOF)
+ return (ferror(f) ? EOF : 0);
+ if (ungetc(magic, f) == EOF)
+ return (EOF);
+ if (magic != 0)
+ /* Old record format. */
+ rv = readrec_v1(f, av2);
+ else
+ /* New record formats. */
+ rv = readrec_vx(f, av2);
+ return (rv == EOF ? EOF : 1);
+}
+
+/*
+ * Read an accounting record ending at the current
+ * position of stream f.
+ * Old-format records are converted to the current record
+ * format.
+ * The file pointer is positioned at the beginning of the
+ * record read.
+ * Return the number of records read (1 or 0 at the end-of-file),
+ * or EOF on error.
+ */
+int
+readrec_backward(FILE *f, struct acctv2 *av2)
+{
+ off_t pos;
+ int c;
+ uint16_t len;
+
+ if ((pos = ftell(f)) == -1)
+ return (EOF);
+ if (pos == 0)
+ return (0);
+ if (fseek(f, -roffsetof(struct acctv2, ac_trailer),
+ SEEK_CUR) == EOF ||
+ (c = getc(f)) == EOF)
+ return (EOF);
+ if (c & ANVER) {
+ /* New record formats. */
+ if (fseeko(f, pos - roffsetof(struct acctv2, ac_len2),
+ SEEK_SET) == EOF ||
+ fread_record(&len, sizeof(len), f) == EOF ||
+ fseeko(f, pos - len, SEEK_SET) == EOF ||
+ readrec_vx(f, av2) == EOF ||
+ fseeko(f, pos - len, SEEK_SET) == EOF)
+ return (EOF);
+ else
+ return (1);
+ } else {
+ /* Old record format. */
+ if (fseeko(f, pos - sizeof(struct acctv1), SEEK_SET) == EOF ||
+ readrec_v1(f, av2) == EOF ||
+ fseeko(f, pos - sizeof(struct acctv1), SEEK_SET) == EOF)
+ return (EOF);
+ else
+ return (1);
+ }
+}
OpenPOWER on IntegriCloud