diff options
author | dds <dds@FreeBSD.org> | 2007-05-22 06:51:38 +0000 |
---|---|---|
committer | dds <dds@FreeBSD.org> | 2007-05-22 06:51:38 +0000 |
commit | 9ed27d10382c7a5e19ef98f5201d68ed00734006 (patch) | |
tree | 22afa8b2db7c7547de2d9babcfaa07cd7d1bbcb6 /usr.bin | |
parent | b6fc65f3b511764ceab1cb5f1d80483816c1fd88 (diff) | |
download | FreeBSD-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')
-rw-r--r-- | usr.bin/lastcomm/Makefile | 1 | ||||
-rw-r--r-- | usr.bin/lastcomm/lastcomm.c | 95 | ||||
-rw-r--r-- | usr.bin/lastcomm/readrec.c | 231 |
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); + } +} |