summaryrefslogtreecommitdiffstats
path: root/usr.bin/lastcomm
diff options
context:
space:
mode:
authordds <dds@FreeBSD.org>2007-05-22 06:51:38 +0000
committerdds <dds@FreeBSD.org>2007-05-22 06:51:38 +0000
commit9ed27d10382c7a5e19ef98f5201d68ed00734006 (patch)
tree22afa8b2db7c7547de2d9babcfaa07cd7d1bbcb6 /usr.bin/lastcomm
parentb6fc65f3b511764ceab1cb5f1d80483816c1fd88 (diff)
downloadFreeBSD-src-9ed27d10382c7a5e19ef98f5201d68ed00734006.zip
FreeBSD-src-9ed27d10382c7a5e19ef98f5201d68ed00734006.tar.gz
Increase precision of time values in the process accounting
structure, while maintaining backward compatibility with legacy file and record formats.
Diffstat (limited to 'usr.bin/lastcomm')
-rw-r--r--usr.bin/lastcomm/Makefile1
-rw-r--r--usr.bin/lastcomm/lastcomm.c95
-rw-r--r--usr.bin/lastcomm/readrec.c231
3 files changed, 260 insertions, 67 deletions
diff --git a/usr.bin/lastcomm/Makefile b/usr.bin/lastcomm/Makefile
index be75109..c79cd74 100644
--- a/usr.bin/lastcomm/Makefile
+++ b/usr.bin/lastcomm/Makefile
@@ -2,6 +2,7 @@
# $FreeBSD$
PROG= lastcomm
+SRCS= lastcomm.c readrec.c
WARNS?= 6
.include <bsd.prog.mk>
diff --git a/usr.bin/lastcomm/lastcomm.c b/usr.bin/lastcomm/lastcomm.c
index 4b0a40f..8c55123 100644
--- a/usr.bin/lastcomm/lastcomm.c
+++ b/usr.bin/lastcomm/lastcomm.c
@@ -51,6 +51,7 @@ __FBSDID("$FreeBSD$");
#include <ctype.h>
#include <err.h>
+#include <errno.h>
#include <fcntl.h>
#include <grp.h>
#include <pwd.h>
@@ -66,7 +67,9 @@ __FBSDID("$FreeBSD$");
time_t expand(u_int);
char *flagbits(int);
const char *getdev(dev_t);
-int requested(char *[], struct acct *);
+int readrec_forward(FILE *f, struct acctv2 *av2);
+int readrec_backward(FILE *f, struct acctv2 *av2);
+int requested(char *[], struct acctv2 *);
static void usage(void);
#define AC_UTIME 1 /* user */
@@ -77,18 +80,15 @@ static void usage(void);
#define AC_BTIME 16 /* starting time */
#define AC_FTIME 32 /* exit time (starting time + elapsed time )*/
-#define AC_HZ ((double)AHZ)
-
int
main(int argc, char *argv[])
{
+ struct acctv2 ab;
char *p;
- struct acct ab;
- struct stat sb;
FILE *fp;
- off_t size;
+ int (*readrec)(FILE *f, struct acctv2 *av2);
time_t t;
- int ch;
+ int ch, rv;
const char *acctfile;
int flags = 0;
@@ -135,78 +135,51 @@ main(int argc, char *argv[])
if (strcmp(acctfile, "-") == 0) {
fp = stdin;
- size = sizeof(struct acct); /* Always one more to read. */
+ readrec = readrec_forward;
} else {
/* Open the file. */
- if ((fp = fopen(acctfile, "r")) == NULL ||
- fstat(fileno(fp), &sb))
+ if ((fp = fopen(acctfile, "r")) == NULL)
err(1, "could not open %s", acctfile);
-
- /*
- * Round off to integral number of accounting records,
- * probably not necessary, but it doesn't hurt.
- */
- size = sb.st_size - sb.st_size % sizeof(struct acct);
-
- /* Check if any records to display. */
- if ((unsigned)size < sizeof(struct acct))
- exit(0);
+ if (fseek(fp, 0l, SEEK_END) == -1)
+ err(1, "seek to end of %s failed", acctfile);
+ readrec = readrec_backward;
}
- do {
- int rv;
+ while ((rv = readrec(fp, &ab)) == 1) {
+ for (p = &ab.ac_comm[0];
+ p < &ab.ac_comm[AC_COMM_LEN] && *p; ++p)
+ if (!isprint(*p))
+ *p = '?';
- if (fp != stdin) {
- size -= sizeof(struct acct);
- if (fseeko(fp, size, SEEK_SET) == -1)
- err(1, "seek %s failed", acctfile);
- }
-
- if ((rv = fread(&ab, sizeof(struct acct), 1, fp)) != 1) {
- if (feof(fp))
- break;
- else
- err(1, "read %s returned %d", acctfile, rv);
- }
-
- if (ab.ac_comm[0] == '\0') {
- ab.ac_comm[0] = '?';
- ab.ac_comm[1] = '\0';
- } else
- for (p = &ab.ac_comm[0];
- p < &ab.ac_comm[AC_COMM_LEN] && *p; ++p)
- if (!isprint(*p))
- *p = '?';
if (*argv && !requested(argv, &ab))
continue;
(void)printf("%-*.*s %-7s %-*s %-*s",
AC_COMM_LEN, AC_COMM_LEN, ab.ac_comm,
- flagbits(ab.ac_flag),
+ flagbits(ab.ac_flagx),
UT_NAMESIZE, user_from_uid(ab.ac_uid, 0),
UT_LINESIZE, getdev(ab.ac_tty));
/* user + system time */
if (flags & AC_CTIME) {
- (void)printf(" %6.2f secs",
- (expand(ab.ac_utime) +
- expand(ab.ac_stime))/AC_HZ);
+ (void)printf(" %6.3f secs",
+ (ab.ac_utime + ab.ac_stime) / 1000000);
}
/* usr time */
if (flags & AC_UTIME) {
- (void)printf(" %6.2f us", expand(ab.ac_utime)/AC_HZ);
+ (void)printf(" %6.3f us", ab.ac_utime / 1000000);
}
/* system time */
if (flags & AC_STIME) {
- (void)printf(" %6.2f sy", expand(ab.ac_stime)/AC_HZ);
+ (void)printf(" %6.3f sy", ab.ac_stime / 1000000);
}
/* elapsed time */
if (flags & AC_ETIME) {
- (void)printf(" %8.2f es", expand(ab.ac_etime)/AC_HZ);
+ (void)printf(" %8.3f es", ab.ac_etime / 1000000);
}
/* starting time */
@@ -217,31 +190,19 @@ main(int argc, char *argv[])
/* exit time (starting time + elapsed time )*/
if (flags & AC_FTIME) {
t = ab.ac_btime;
- t += (time_t)(expand(ab.ac_etime)/AC_HZ);
+ t += (time_t)(ab.ac_etime / 1000000);
(void)printf(" %.16s", ctime(&t));
}
printf("\n");
+ }
+ if (rv == EOF)
+ err(1, "read record from %s failed", acctfile);
- } while (size > 0);
if (fflush(stdout))
err(1, "stdout");
exit(0);
}
-time_t
-expand(u_int t)
-{
- time_t nt;
-
- nt = t & 017777;
- t >>= 13;
- while (t) {
- t--;
- nt <<= 3;
- }
- return (nt);
-}
-
char *
flagbits(int f)
{
@@ -261,7 +222,7 @@ flagbits(int f)
}
int
-requested(char *argv[], struct acct *acp)
+requested(char *argv[], struct acctv2 *acp)
{
const char *p;
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