summaryrefslogtreecommitdiffstats
path: root/usr.sbin/sa
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.sbin/sa
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.sbin/sa')
-rw-r--r--usr.sbin/sa/Makefile4
-rw-r--r--usr.sbin/sa/db.c207
-rw-r--r--usr.sbin/sa/extern.h34
-rw-r--r--usr.sbin/sa/main.c110
-rw-r--r--usr.sbin/sa/pdb.c170
-rw-r--r--usr.sbin/sa/usrdb.c177
6 files changed, 406 insertions, 296 deletions
diff --git a/usr.sbin/sa/Makefile b/usr.sbin/sa/Makefile
index 994e0dd..ae6af5a 100644
--- a/usr.sbin/sa/Makefile
+++ b/usr.sbin/sa/Makefile
@@ -2,8 +2,10 @@
PROG= sa
MAN= sa.8
-SRCS= main.c pdb.c usrdb.c
+SRCS= main.c db.c pdb.c usrdb.c readrec.c
WARNS?= 6
+.PATH: ${.CURDIR}/../../usr.bin/lastcomm
+
.include <bsd.prog.mk>
diff --git a/usr.sbin/sa/db.c b/usr.sbin/sa/db.c
new file mode 100644
index 0000000..d31cd7c
--- /dev/null
+++ b/usr.sbin/sa/db.c
@@ -0,0 +1,207 @@
+/*-
+ * 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/types.h>
+#include <sys/acct.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <db.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#include "extern.h"
+
+/* Key used to store the version of the database data elements. */
+#define VERSION_KEY "\0VERSION"
+
+/*
+ * Create the in-memory database, *mdb.
+ * If iflag is not set, fill-in mdb with the records of the disk-based
+ * database dbname.
+ * Upgrade old-version records by calling v1_to_v2.
+ * Return 0 if OK, -1 on error.
+ */
+int
+db_copy_in(DB **mdb, const char *dbname, const char *uname, BTREEINFO *bti,
+ int (*v1_to_v2)(DBT *key, DBT *data))
+{
+ DBT key, data;
+ DB *ddb;
+ int error, rv, version;
+
+ if ((*mdb = dbopen(NULL, O_RDWR, 0, DB_BTREE, bti)) == NULL)
+ return (-1);
+
+ if (iflag)
+ return (0);
+
+ if ((ddb = dbopen(dbname, O_RDONLY, 0, DB_BTREE, NULL)) == NULL) {
+ if (errno == ENOENT)
+ return (0);
+ warn("retrieving %s summary", uname);
+ db_destroy(*mdb, uname);
+ return (-1);
+ }
+
+ error = 0;
+
+ /* Obtain/set version. */
+ version = 1;
+ key.data = &VERSION_KEY;
+ key.size = sizeof(VERSION_KEY);
+
+ rv = DB_GET(ddb, &key, &data, 0);
+ if (rv < 0) {
+ warn("get version key from %s stats", uname);
+ error = -1;
+ goto closeout;
+ } else if (rv == 0) { /* It's there; verify version. */
+ if (data.size != sizeof(version)) {
+ warnx("invalid version size %d in %s",
+ data.size, uname);
+ error = -1;
+ goto closeout;
+ }
+ memcpy(&version, data.data, data.size);
+ if (version != 2) {
+ warnx("unsupported version %d in %s",
+ version, uname);
+ error = -1;
+ goto closeout;
+ }
+ }
+
+ for (rv = DB_SEQ(ddb, &key, &data, R_FIRST); rv == 0;
+ rv = DB_SEQ(ddb, &key, &data, R_NEXT)) {
+
+ /* See if this is a version record. */
+ if (key.size == sizeof(VERSION_KEY) &&
+ memcmp(key.data, VERSION_KEY, sizeof(VERSION_KEY)) == 0)
+ continue;
+
+ /* Convert record from v1, if needed. */
+ if (version == 1 && v1_to_v2(&key, &data) < 0) {
+ warn("converting %s stats", uname);
+ error = -1;
+ goto closeout;
+ }
+
+ /* Copy record to the in-memory database. */
+ if ((rv = DB_PUT(*mdb, &key, &data, 0)) < 0) {
+ warn("initializing %s stats", uname);
+ error = -1;
+ goto closeout;
+ }
+ }
+ if (rv < 0) {
+ warn("retrieving %s summary", uname);
+ error = -1;
+ }
+
+closeout:
+ if (DB_CLOSE(ddb) < 0) {
+ warn("closing %s summary", uname);
+ error = -1;
+ }
+
+ if (error)
+ db_destroy(*mdb, uname);
+ return (error);
+}
+
+/*
+ * Save the in-memory database mdb to the disk database dbname.
+ * Return 0 if OK, -1 on error.
+ */
+int
+db_copy_out(DB *mdb, const char *dbname, const char *uname, BTREEINFO *bti)
+{
+ DB *ddb;
+ DBT key, data;
+ int error, rv, version;
+
+ if ((ddb = dbopen(dbname, O_RDWR|O_CREAT|O_TRUNC, 0644,
+ DB_BTREE, bti)) == NULL) {
+ warn("creating %s summary", uname);
+ return (-1);
+ }
+
+ error = 0;
+
+ for (rv = DB_SEQ(mdb, &key, &data, R_FIRST);
+ rv == 0; rv = DB_SEQ(mdb, &key, &data, R_NEXT)) {
+ if ((rv = DB_PUT(ddb, &key, &data, 0)) < 0) {
+ warn("saving %s summary", uname);
+ error = -1;
+ goto out;
+ }
+ }
+ if (rv < 0) {
+ warn("retrieving %s stats", uname);
+ error = -1;
+ }
+
+out:
+ /* Add a version record. */
+ key.data = &VERSION_KEY;
+ key.size = sizeof(VERSION_KEY);
+ version = 2;
+ data.data = &version;
+ data.size = sizeof(version);
+ if ((rv = DB_PUT(ddb, &key, &data, 0)) < 0) {
+ warn("add version record to %s stats", uname);
+ error = -1;
+ } else if (rv == 1) {
+ warnx("duplicate version record in %s stats", uname);
+ error = -1;
+ }
+
+ if (DB_SYNC(ddb, 0) < 0) {
+ warn("syncing %s summary", uname);
+ error = -1;
+ }
+ if (DB_CLOSE(ddb) < 0) {
+ warn("closing %s summary", uname);
+ error = -1;
+ }
+ return error;
+}
+
+void
+db_destroy(DB *db, const char *uname)
+{
+ if (DB_CLOSE(db) < 0)
+ warn("destroying %s stats", uname);
+}
diff --git a/usr.sbin/sa/extern.h b/usr.sbin/sa/extern.h
index ccdd763..70f97a7 100644
--- a/usr.sbin/sa/extern.h
+++ b/usr.sbin/sa/extern.h
@@ -36,32 +36,41 @@
/* structures */
+/* All times are stored in 1e-6s units. */
+
struct cmdinfo {
char ci_comm[MAXCOMLEN+2]; /* command name (+ '*') */
- u_long ci_uid; /* user id */
+ uid_t ci_uid; /* user id */
u_quad_t ci_calls; /* number of calls */
- u_quad_t ci_etime; /* elapsed time */
- u_quad_t ci_utime; /* user time */
- u_quad_t ci_stime; /* system time */
- u_quad_t ci_mem; /* memory use */
- u_quad_t ci_io; /* number of disk i/o ops */
+ double ci_etime; /* elapsed time */
+ double ci_utime; /* user time */
+ double ci_stime; /* system time */
+ double ci_mem; /* memory use */
+ double ci_io; /* number of disk i/o ops */
u_int ci_flags; /* flags; see below */
};
#define CI_UNPRINTABLE 0x0001 /* unprintable chars in name */
struct userinfo {
- u_long ui_uid; /* user id; for consistency */
+ uid_t ui_uid; /* user id; for consistency */
u_quad_t ui_calls; /* number of invocations */
- u_quad_t ui_utime; /* user time */
- u_quad_t ui_stime; /* system time */
- u_quad_t ui_mem; /* memory use */
- u_quad_t ui_io; /* number of disk i/o ops */
+ double ui_utime; /* user time */
+ double ui_stime; /* system time */
+ double ui_mem; /* memory use */
+ double ui_io; /* number of disk i/o ops */
};
/* typedefs */
typedef int (*cmpf_t)(const DBT *, const DBT *);
+/* external functions in db.c */
+int db_copy_in(DB **mdb, const char *dbname, const char *name,
+ BTREEINFO *bti, int (*v1_to_v2)(DBT *key, DBT *data));
+int db_copy_out(DB *mdb, const char *dbname, const char *name,
+ BTREEINFO *bti);
+void db_destroy(DB *db, const char *uname);
+
/* external functions in pdb.c */
int pacct_init(void);
void pacct_destroy(void);
@@ -69,6 +78,9 @@ int pacct_add(const struct cmdinfo *);
int pacct_update(void);
void pacct_print(void);
+/* external functions in readrec.c */
+int readrec_forward(FILE *f, struct acctv2 *av2);
+
/* external functions in usrdb.c */
int usracct_init(void);
void usracct_destroy(void);
diff --git a/usr.sbin/sa/main.c b/usr.sbin/sa/main.c
index 3e10c1b..7be13e5 100644
--- a/usr.sbin/sa/main.c
+++ b/usr.sbin/sa/main.c
@@ -46,6 +46,7 @@ __FBSDID("$FreeBSD$");
#include <sys/acct.h>
#include <ctype.h>
#include <err.h>
+#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <stdint.h>
@@ -56,17 +57,16 @@ __FBSDID("$FreeBSD$");
#include "extern.h"
#include "pathnames.h"
-static int acct_load(const char *, int);
-static u_quad_t decode_comp_t(comp_t);
-static int cmp_comm(const char *, const char *);
-static int cmp_usrsys(const DBT *, const DBT *);
-static int cmp_avgusrsys(const DBT *, const DBT *);
-static int cmp_dkio(const DBT *, const DBT *);
-static int cmp_avgdkio(const DBT *, const DBT *);
-static int cmp_cpumem(const DBT *, const DBT *);
-static int cmp_avgcpumem(const DBT *, const DBT *);
-static int cmp_calls(const DBT *, const DBT *);
-static void usage(void);
+static FILE *acct_load(const char *, int);
+static int cmp_comm(const char *, const char *);
+static int cmp_usrsys(const DBT *, const DBT *);
+static int cmp_avgusrsys(const DBT *, const DBT *);
+static int cmp_dkio(const DBT *, const DBT *);
+static int cmp_avgdkio(const DBT *, const DBT *);
+static int cmp_cpumem(const DBT *, const DBT *);
+static int cmp_avgcpumem(const DBT *, const DBT *);
+static int cmp_calls(const DBT *, const DBT *);
+static void usage(void);
int aflag, bflag, cflag, dflag, Dflag, fflag, iflag, jflag, kflag;
int Kflag, lflag, mflag, qflag, rflag, sflag, tflag, uflag, vflag;
@@ -83,6 +83,7 @@ cmpf_t sa_cmp = cmp_usrsys;
int
main(int argc, char **argv)
{
+ FILE *f;
char pathacct[] = _PATH_ACCT;
int ch, error = 0;
@@ -210,14 +211,12 @@ main(int argc, char **argv)
/* for each file specified */
for (; argc > 0; argc--, argv++) {
- int fd;
-
/*
* load the accounting data from the file.
* if it fails, go on to the next file.
*/
- fd = acct_load(argv[0], sflag);
- if (fd < 0)
+ f = acct_load(argv[0], sflag);
+ if (f == NULL)
continue;
if (!uflag && sflag) {
@@ -248,7 +247,7 @@ main(int argc, char **argv)
* the saved stats; better to underbill than overbill,
* but we want every accounting record intact.
*/
- if (ftruncate(fd, 0) == -1) {
+ if (ftruncate(fileno(f), 0) == -1) {
warn("couldn't truncate %s", *argv);
error = 1;
}
@@ -275,8 +274,8 @@ main(int argc, char **argv)
/*
* close the opened accounting file
*/
- if (close(fd) == -1) {
- warn("close %s", *argv);
+ if (fclose(f) == EOF) {
+ warn("fclose %s", *argv);
error = 1;
}
}
@@ -308,21 +307,22 @@ usage()
exit(1);
}
-static int
+static FILE *
acct_load(const char *pn, int wr)
{
- struct acct ac;
+ struct acctv2 ac;
struct cmdinfo ci;
ssize_t rv;
- int fd, i;
+ FILE *f;
+ int i;
/*
* open the file
*/
- fd = open(pn, wr ? O_RDWR : O_RDONLY, 0);
- if (fd == -1) {
+ f = fopen(pn, wr ? "r+" : "r");
+ if (f == NULL) {
warn("open %s %s", pn, wr ? "for read/write" : "read-only");
- return (-1);
+ return (NULL);
}
/*
@@ -331,13 +331,12 @@ acct_load(const char *pn, int wr)
*/
while (1) {
/* get one accounting entry and punt if there's an error */
- rv = read(fd, &ac, sizeof(struct acct));
- if (rv == -1)
- warn("error reading %s", pn);
- else if (rv > 0 && rv < (int)sizeof(struct acct))
- warnx("short read of accounting data in %s", pn);
- if (rv != sizeof(struct acct))
+ rv = readrec_forward(f, &ac);
+ if (rv != 1) {
+ if (rv == EOF)
+ warn("error reading %s", pn);
break;
+ }
/* decode it */
ci.ci_calls = 1;
@@ -351,15 +350,15 @@ acct_load(const char *pn, int wr)
} else
ci.ci_comm[i] = c;
}
- if (ac.ac_flag & AFORK)
+ if (ac.ac_flagx & AFORK)
ci.ci_comm[i++] = '*';
ci.ci_comm[i++] = '\0';
- ci.ci_etime = decode_comp_t(ac.ac_etime);
- ci.ci_utime = decode_comp_t(ac.ac_utime);
- ci.ci_stime = decode_comp_t(ac.ac_stime);
+ ci.ci_etime = ac.ac_etime;
+ ci.ci_utime = ac.ac_utime;
+ ci.ci_stime = ac.ac_stime;
ci.ci_uid = ac.ac_uid;
ci.ci_mem = ac.ac_mem;
- ci.ci_io = decode_comp_t(ac.ac_io) / AHZ;
+ ci.ci_io = ac.ac_io;
if (!uflag) {
/* and enter it into the usracct and pacct databases */
@@ -368,34 +367,15 @@ acct_load(const char *pn, int wr)
if (sflag || (mflag && !qflag))
usracct_add(&ci);
} else if (!qflag)
- printf("%6lu %12.2f cpu %12juk mem %12ju io %s\n",
+ printf("%6u %12.3lf cpu %12.0lfk mem %12.0lf io %s\n",
ci.ci_uid,
- (ci.ci_utime + ci.ci_stime) / (double) AHZ,
- (uintmax_t)ci.ci_mem, (uintmax_t)ci.ci_io,
+ (ci.ci_utime + ci.ci_stime) / 1000000,
+ ci.ci_mem, ci.ci_io,
ci.ci_comm);
}
- /* finally, return the file descriptor for possible truncation */
- return (fd);
-}
-
-static u_quad_t
-decode_comp_t(comp_t comp)
-{
- u_quad_t rv;
-
- /*
- * for more info on the comp_t format, see:
- * /usr/src/sys/kern/kern_acct.c
- * /usr/src/sys/sys/acct.h
- * /usr/src/usr.bin/lastcomm/lastcomm.c
- */
- rv = comp & 0x1fff; /* 13 bit fraction */
- comp >>= 13; /* 3 bit base-8 exponent */
- while (comp--)
- rv <<= 3;
-
- return (rv);
+ /* Finally, return the file stream for possible truncation. */
+ return (f);
}
/* sort commands, doing the right thing in terms of reversals */
@@ -415,7 +395,7 @@ static int
cmp_usrsys(const DBT *d1, const DBT *d2)
{
struct cmdinfo c1, c2;
- u_quad_t t1, t2;
+ double t1, t2;
memcpy(&c1, d1->data, sizeof(c1));
memcpy(&c2, d2->data, sizeof(c2));
@@ -482,8 +462,8 @@ cmp_avgdkio(const DBT *d1, const DBT *d2)
memcpy(&c1, d1->data, sizeof(c1));
memcpy(&c2, d2->data, sizeof(c2));
- n1 = (double) c1.ci_io / (double) (c1.ci_calls ? c1.ci_calls : 1);
- n2 = (double) c2.ci_io / (double) (c2.ci_calls ? c2.ci_calls : 1);
+ n1 = c1.ci_io / (double) (c1.ci_calls ? c1.ci_calls : 1);
+ n2 = c2.ci_io / (double) (c2.ci_calls ? c2.ci_calls : 1);
if (n1 < n2)
return -1;
@@ -515,7 +495,7 @@ static int
cmp_avgcpumem(const DBT *d1, const DBT *d2)
{
struct cmdinfo c1, c2;
- u_quad_t t1, t2;
+ double t1, t2;
double n1, n2;
memcpy(&c1, d1->data, sizeof(c1));
@@ -524,8 +504,8 @@ cmp_avgcpumem(const DBT *d1, const DBT *d2)
t1 = c1.ci_utime + c1.ci_stime;
t2 = c2.ci_utime + c2.ci_stime;
- n1 = (double) c1.ci_mem / (double) (t1 ? t1 : 1);
- n2 = (double) c2.ci_mem / (double) (t2 ? t2 : 1);
+ n1 = c1.ci_mem / (t1 ? t1 : 1);
+ n2 = c2.ci_mem / (t2 ? t2 : 1);
if (n1 < n2)
return -1;
diff --git a/usr.sbin/sa/pdb.c b/usr.sbin/sa/pdb.c
index 0c92d34..38beb55 100644
--- a/usr.sbin/sa/pdb.c
+++ b/usr.sbin/sa/pdb.c
@@ -36,6 +36,7 @@ __FBSDID("$FreeBSD$");
#include <err.h>
#include <errno.h>
#include <fcntl.h>
+#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
@@ -48,68 +49,61 @@ static void print_ci(const struct cmdinfo *, const struct cmdinfo *);
static DB *pacct_db;
-int
-pacct_init()
+/* Legacy format in AHZV1 units. */
+struct cmdinfov1 {
+ char ci_comm[MAXCOMLEN+2]; /* command name (+ '*') */
+ uid_t ci_uid; /* user id */
+ u_quad_t ci_calls; /* number of calls */
+ u_quad_t ci_etime; /* elapsed time */
+ u_quad_t ci_utime; /* user time */
+ u_quad_t ci_stime; /* system time */
+ u_quad_t ci_mem; /* memory use */
+ u_quad_t ci_io; /* number of disk i/o ops */
+ u_int ci_flags; /* flags; see below */
+};
+
+/*
+ * Convert a v1 data record into the current version.
+ * Return 0 if OK, -1 on error, setting errno.
+ */
+static int
+v1_to_v2(DBT *key __unused, DBT *data)
{
- DB *saved_pacct_db;
- int error;
+ struct cmdinfov1 civ1;
+ static struct cmdinfo civ2;
- pacct_db = dbopen(NULL, O_RDWR, 0, DB_BTREE, NULL);
- if (pacct_db == NULL)
+ if (data->size != sizeof(civ1)) {
+ errno = EFTYPE;
return (-1);
-
- error = 0;
- if (!iflag) {
- DBT key, data;
- int serr, nerr;
-
- saved_pacct_db = dbopen(pdb_file, O_RDONLY, 0, DB_BTREE,
- NULL);
- if (saved_pacct_db == NULL) {
- error = errno == ENOENT ? 0 : -1;
- if (error)
- warn("retrieving process accounting summary");
- goto out;
- }
-
- serr = DB_SEQ(saved_pacct_db, &key, &data, R_FIRST);
- if (serr < 0) {
- warn("retrieving process accounting summary");
- error = -1;
- goto closeout;
- }
- while (serr == 0) {
- nerr = DB_PUT(pacct_db, &key, &data, 0);
- if (nerr < 0) {
- warn("initializing process accounting stats");
- error = -1;
- break;
- }
-
- serr = DB_SEQ(saved_pacct_db, &key, &data, R_NEXT);
- if (serr < 0) {
- warn("retrieving process accounting summary");
- error = -1;
- break;
- }
- }
-
-closeout: if (DB_CLOSE(saved_pacct_db) < 0) {
- warn("closing process accounting summary");
- error = -1;
- }
}
+ memcpy(&civ1, data->data, data->size);
+ memset(&civ2, 0, sizeof(civ2));
+ memcpy(civ2.ci_comm, civ1.ci_comm, sizeof(civ2.ci_comm));
+ civ2.ci_uid = civ1.ci_uid;
+ civ2.ci_calls = civ1.ci_calls;
+ civ2.ci_etime = ((double)civ1.ci_etime / AHZV1) * 1000000;
+ civ2.ci_utime = ((double)civ1.ci_utime / AHZV1) * 1000000;
+ civ2.ci_stime = ((double)civ1.ci_stime / AHZV1) * 1000000;
+ civ2.ci_mem = civ1.ci_mem;
+ civ2.ci_io = civ1.ci_io;
+ civ2.ci_flags = civ1.ci_flags;
+ data->size = sizeof(civ2);
+ data->data = &civ2;
+ return (0);
+}
-out: if (error != 0)
- pacct_destroy();
- return (error);
+/* Copy pdb_file to in-memory pacct_db. */
+int
+pacct_init()
+{
+ return (db_copy_in(&pacct_db, pdb_file, "process accounting",
+ NULL, v1_to_v2));
}
void
pacct_destroy()
{
- if (DB_CLOSE(pacct_db) < 0)
- warn("destroying process accounting stats");
+ db_destroy(pacct_db, "process accounting");
}
int
@@ -154,52 +148,12 @@ pacct_add(const struct cmdinfo *ci)
return (0);
}
+/* Copy in-memory pacct_db to pdb_file. */
int
pacct_update()
{
- DB *saved_pacct_db;
- DBT key, data;
- int error, serr, nerr;
-
- saved_pacct_db = dbopen(pdb_file, O_RDWR|O_CREAT|O_TRUNC, 0644,
- DB_BTREE, NULL);
- if (saved_pacct_db == NULL) {
- warn("creating process accounting summary");
- return (-1);
- }
-
- error = 0;
-
- serr = DB_SEQ(pacct_db, &key, &data, R_FIRST);
- if (serr < 0) {
- warn("retrieving process accounting stats");
- error = -1;
- }
- while (serr == 0) {
- nerr = DB_PUT(saved_pacct_db, &key, &data, 0);
- if (nerr < 0) {
- warn("saving process accounting summary");
- error = -1;
- break;
- }
-
- serr = DB_SEQ(pacct_db, &key, &data, R_NEXT);
- if (serr < 0) {
- warn("retrieving process accounting stats");
- error = -1;
- break;
- }
- }
-
- if (DB_SYNC(saved_pacct_db, 0) < 0) {
- warn("syncing process accounting summary");
- error = -1;
- }
- if (DB_CLOSE(saved_pacct_db) < 0) {
- warn("closing process accounting summary");
- error = -1;
- }
- return error;
+ return (db_copy_out(pacct_db, pdb_file, "process accounting",
+ NULL));
}
void
@@ -330,7 +284,7 @@ print_ci(const struct cmdinfo *cip, const struct cmdinfo *totalcip)
int uflow;
c = cip->ci_calls ? cip->ci_calls : 1;
- t = (cip->ci_utime + cip->ci_stime) / (double) AHZ;
+ t = (cip->ci_utime + cip->ci_stime) / 1000000;
if (t < 0.01) {
t = 0.01;
uflow = 1;
@@ -347,26 +301,26 @@ print_ci(const struct cmdinfo *cip, const struct cmdinfo *totalcip)
}
if (jflag)
- printf("%11.2fre ", cip->ci_etime / (double) (AHZ * c));
+ printf("%11.3fre ", cip->ci_etime / (1000000 * c));
else
- printf("%11.2fre ", cip->ci_etime / (60.0 * AHZ));
+ printf("%11.3fre ", cip->ci_etime / (60.0 * 1000000));
if (cflag) {
if (cip != totalcip)
printf(" %4.1f%% ", cip->ci_etime /
- (double)totalcip->ci_etime * 100);
+ totalcip->ci_etime * 100);
else
printf(" %4s ", "");
}
if (!lflag) {
if (jflag)
- printf("%11.2fcp ", t / (double) cip->ci_calls);
+ printf("%11.3fcp ", t / (double) cip->ci_calls);
else
printf("%11.2fcp ", t / 60.0);
if (cflag) {
if (cip != totalcip)
printf(" %4.1f%% ",
- (double)(cip->ci_utime + cip->ci_stime) /
+ (cip->ci_utime + cip->ci_stime) /
(totalcip->ci_utime + totalcip->ci_stime) *
100);
else
@@ -374,9 +328,9 @@ print_ci(const struct cmdinfo *cip, const struct cmdinfo *totalcip)
}
} else {
if (jflag)
- printf("%11.2fu ", cip->ci_utime / (double) (AHZ * c));
+ printf("%11.3fu ", cip->ci_utime / (1000000 * c));
else
- printf("%11.2fu ", cip->ci_utime / (60.0 * AHZ));
+ printf("%11.2fu ", cip->ci_utime / (60.0 * 1000000));
if (cflag) {
if (cip != totalcip)
printf(" %4.1f%% ", cip->ci_utime /
@@ -385,9 +339,9 @@ print_ci(const struct cmdinfo *cip, const struct cmdinfo *totalcip)
printf(" %4s ", "");
}
if (jflag)
- printf("%11.2fs ", cip->ci_stime / (double) (AHZ * c));
+ printf("%11.3fs ", cip->ci_stime / (1000000 * c));
else
- printf("%11.2fs ", cip->ci_stime / (60.0 * AHZ));
+ printf("%11.2fs ", cip->ci_stime / (60.0 * 1000000));
if (cflag) {
if (cip != totalcip)
printf(" %4.1f%% ", cip->ci_stime /
@@ -401,18 +355,18 @@ print_ci(const struct cmdinfo *cip, const struct cmdinfo *totalcip)
if (!uflow)
printf("%8.2fre/cp ",
cip->ci_etime /
- (double) (cip->ci_utime + cip->ci_stime));
+ (cip->ci_utime + cip->ci_stime));
else
printf("*ignore* ");
}
if (Dflag)
- printf("%10jutio ", (uintmax_t)cip->ci_io);
+ printf("%10.0fio ", cip->ci_io);
else
printf("%8.0favio ", cip->ci_io / c);
if (Kflag)
- printf("%10juk*sec ", (uintmax_t)cip->ci_mem);
+ printf("%10.0fk*sec ", cip->ci_mem);
else
printf("%8.0fk ", cip->ci_mem / t);
diff --git a/usr.sbin/sa/usrdb.c b/usr.sbin/sa/usrdb.c
index 2f76d65..07a5033 100644
--- a/usr.sbin/sa/usrdb.c
+++ b/usr.sbin/sa/usrdb.c
@@ -49,74 +49,69 @@ static int uid_compare(const DBT *, const DBT *);
static DB *usracct_db;
+/* Legacy format in AHZV1 units. */
+struct userinfov1 {
+ uid_t ui_uid; /* user id; for consistency */
+ u_quad_t ui_calls; /* number of invocations */
+ u_quad_t ui_utime; /* user time */
+ u_quad_t ui_stime; /* system time */
+ u_quad_t ui_mem; /* memory use */
+ u_quad_t ui_io; /* number of disk i/o ops */
+};
+
+/*
+ * Convert a v1 data record into the current version.
+ * Return 0 if OK, -1 on error, setting errno.
+ */
+static int
+v1_to_v2(DBT *key, DBT *data)
+{
+ struct userinfov1 uiv1;
+ static struct userinfo uiv2;
+ static uid_t uid;
+
+ if (key->size != sizeof(u_long) || data->size != sizeof(uiv1)) {
+ errno = EFTYPE;
+ return (-1);
+ }
+
+ /* Convert key. */
+ key->size = sizeof(uid_t);
+ uid = (uid_t)*(u_long *)(key->data);
+ key->data = &uid;
+
+ /* Convert data. */
+ memcpy(&uiv1, data->data, data->size);
+ memset(&uiv2, 0, sizeof(uiv2));
+ uiv2.ui_uid = uiv1.ui_uid;
+ uiv2.ui_calls = uiv1.ui_calls;
+ uiv2.ui_utime = ((double)uiv1.ui_utime / AHZV1) * 1000000;
+ uiv2.ui_stime = ((double)uiv1.ui_stime / AHZV1) * 1000000;
+ uiv2.ui_mem = uiv1.ui_mem;
+ uiv2.ui_io = uiv1.ui_io;
+ data->size = sizeof(uiv2);
+ data->data = &uiv2;
+
+ return (0);
+}
+
+/* Copy usrdb_file to in-memory usracct_db. */
int
usracct_init()
{
- DB *saved_usracct_db;
BTREEINFO bti;
- int error;
bzero(&bti, sizeof bti);
bti.compare = uid_compare;
- usracct_db = dbopen(NULL, O_RDWR, 0, DB_BTREE, &bti);
- if (usracct_db == NULL)
- return (-1);
-
- error = 0;
- if (!iflag) {
- DBT key, data;
- int serr, nerr;
-
- saved_usracct_db = dbopen(usrdb_file, O_RDONLY, 0, DB_BTREE,
- &bti);
- if (saved_usracct_db == NULL) {
- error = (errno == ENOENT) ? 0 : -1;
- if (error)
- warn("retrieving user accounting summary");
- goto out;
- }
-
- serr = DB_SEQ(saved_usracct_db, &key, &data, R_FIRST);
- if (serr < 0) {
- warn("retrieving user accounting summary");
- error = -1;
- goto closeout;
- }
- while (serr == 0) {
- nerr = DB_PUT(usracct_db, &key, &data, 0);
- if (nerr < 0) {
- warn("initializing user accounting stats");
- error = -1;
- break;
- }
-
- serr = DB_SEQ(saved_usracct_db, &key, &data, R_NEXT);
- if (serr < 0) {
- warn("retrieving user accounting summary");
- error = -1;
- break;
- }
- }
-
-closeout:
- if (DB_CLOSE(saved_usracct_db) < 0) {
- warn("closing user accounting summary");
- error = -1;
- }
- }
-
-out:
- if (error != 0)
- usracct_destroy();
- return (error);
+ return (db_copy_in(&usracct_db, usrdb_file, "user accounting",
+ &bti, v1_to_v2));
}
void
usracct_destroy()
{
- if (DB_CLOSE(usracct_db) < 0)
- warn("destroying user accounting stats");
+ db_destroy(usracct_db, "user accounting");
}
int
@@ -124,7 +119,7 @@ usracct_add(const struct cmdinfo *ci)
{
DBT key, data;
struct userinfo newui;
- u_long uid;
+ uid_t uid;
int rv;
uid = ci->ci_uid;
@@ -133,13 +128,13 @@ usracct_add(const struct cmdinfo *ci)
rv = DB_GET(usracct_db, &key, &data, 0);
if (rv < 0) {
- warn("get key %lu from user accounting stats", uid);
+ warn("get key %u from user accounting stats", uid);
return (-1);
} else if (rv == 0) { /* it's there; copy whole thing */
/* add the old data to the new data */
bcopy(data.data, &newui, data.size);
if (newui.ui_uid != uid) {
- warnx("key %lu != expected record number %lu",
+ warnx("key %u != expected record number %u",
newui.ui_uid, uid);
warnx("inconsistent user accounting stats");
return (-1);
@@ -159,7 +154,7 @@ usracct_add(const struct cmdinfo *ci)
data.size = sizeof newui;
rv = DB_PUT(usracct_db, &key, &data, 0);
if (rv < 0) {
- warn("add key %lu to user accounting stats", uid);
+ warn("add key %u to user accounting stats", uid);
return (-1);
} else if (rv != 0) {
warnx("DB_PUT returned 1");
@@ -169,56 +164,17 @@ usracct_add(const struct cmdinfo *ci)
return (0);
}
+/* Copy in-memory usracct_db to usrdb_file. */
int
usracct_update()
{
- DB *saved_usracct_db;
- DBT key, data;
BTREEINFO bti;
- int error, serr, nerr;
bzero(&bti, sizeof bti);
bti.compare = uid_compare;
- saved_usracct_db = dbopen(usrdb_file, O_RDWR|O_CREAT|O_TRUNC, 0644,
- DB_BTREE, &bti);
- if (saved_usracct_db == NULL) {
- warn("creating user accounting summary");
- return (-1);
- }
-
- error = 0;
-
- serr = DB_SEQ(usracct_db, &key, &data, R_FIRST);
- if (serr < 0) {
- warn("retrieving user accounting stats");
- error = -1;
- }
- while (serr == 0) {
- nerr = DB_PUT(saved_usracct_db, &key, &data, 0);
- if (nerr < 0) {
- warn("saving user accounting summary");
- error = -1;
- break;
- }
-
- serr = DB_SEQ(usracct_db, &key, &data, R_NEXT);
- if (serr < 0) {
- warn("retrieving user accounting stats");
- error = -1;
- break;
- }
- }
-
- if (DB_SYNC(saved_usracct_db, 0) < 0) {
- warn("syncing process accounting summary");
- error = -1;
- }
- if (DB_CLOSE(saved_usracct_db) < 0) {
- warn("closing process accounting summary");
- error = -1;
- }
- return error;
+ return (db_copy_out(usracct_db, usrdb_file, "user accounting",
+ &bti));
}
void
@@ -239,25 +195,24 @@ usracct_print()
printf("%-*s %9ju ", MAXLOGNAME - 1,
user_from_uid(ui->ui_uid, 0), (uintmax_t)ui->ui_calls);
- t = (double) (ui->ui_utime + ui->ui_stime) /
- (double) AHZ;
- if (t < 0.0001) /* kill divide by zero */
- t = 0.0001;
+ t = (ui->ui_utime + ui->ui_stime) / 1000000;
+ if (t < 0.000001) /* kill divide by zero */
+ t = 0.000001;
printf("%12.2f%s ", t / 60.0, "cpu");
/* ui->ui_calls is always != 0 */
if (dflag)
- printf("%12ju%s",
- (uintmax_t)(ui->ui_io / ui->ui_calls), "avio");
+ printf("%12.0f%s",
+ ui->ui_io / ui->ui_calls, "avio");
else
- printf("%12ju%s", (uintmax_t)ui->ui_io, "tio");
+ printf("%12.0f%s", ui->ui_io, "tio");
- /* t is always >= 0.0001; see above */
+ /* t is always >= 0.000001; see above. */
if (kflag)
printf("%12.0f%s", ui->ui_mem / t, "k");
else
- printf("%12ju%s", (uintmax_t)ui->ui_mem, "k*sec");
+ printf("%12.0f%s", ui->ui_mem, "k*sec");
printf("\n");
@@ -270,7 +225,7 @@ usracct_print()
static int
uid_compare(const DBT *k1, const DBT *k2)
{
- u_long d1, d2;
+ uid_t d1, d2;
bcopy(k1->data, &d1, sizeof d1);
bcopy(k2->data, &d2, sizeof d2);
OpenPOWER on IntegriCloud