mirror of
https://git.FreeBSD.org/src.git
synced 2025-02-05 18:05:16 +00:00
Increase precision of time values in the process accounting
structure, while maintaining backward compatibility with legacy file and record formats.
This commit is contained in:
parent
550bfecc8f
commit
fdbe5babe4
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=169857
@ -32,7 +32,7 @@
|
|||||||
.\" @(#)acct.5 8.1 (Berkeley) 6/5/93
|
.\" @(#)acct.5 8.1 (Berkeley) 6/5/93
|
||||||
.\" $FreeBSD$
|
.\" $FreeBSD$
|
||||||
.\"
|
.\"
|
||||||
.Dd June 5, 1993
|
.Dd May 15, 2007
|
||||||
.Dt ACCT 5
|
.Dt ACCT 5
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
@ -52,38 +52,47 @@ the kernel calls the
|
|||||||
function call to prepare and append the record
|
function call to prepare and append the record
|
||||||
to the accounting file.
|
to the accounting file.
|
||||||
.Bd -literal
|
.Bd -literal
|
||||||
/*
|
|
||||||
* Accounting structures; these use a comp_t type which is a 3 bits base 8
|
|
||||||
* exponent, 13 bit fraction ``floating point'' number. Units are 1/AHZ
|
|
||||||
* seconds.
|
|
||||||
*/
|
|
||||||
typedef u_short comp_t;
|
|
||||||
|
|
||||||
#define AC_COMM_LEN 16
|
#define AC_COMM_LEN 16
|
||||||
struct acct {
|
|
||||||
char ac_comm[AC_COMM_LEN]; /* command name */
|
|
||||||
comp_t ac_utime; /* user time */
|
|
||||||
comp_t ac_stime; /* system time */
|
|
||||||
comp_t ac_etime; /* elapsed time */
|
|
||||||
time_t ac_btime; /* starting time */
|
|
||||||
uid_t ac_uid; /* user id */
|
|
||||||
gid_t ac_gid; /* group id */
|
|
||||||
short ac_mem; /* average memory usage */
|
|
||||||
comp_t ac_io; /* count of IO blocks */
|
|
||||||
dev_t ac_tty; /* controlling tty */
|
|
||||||
#define AFORK 0x01 /* forked but not exec'ed */
|
|
||||||
#define ASU 0x02 /* used super-user permissions */
|
|
||||||
#define ACOMPAT 0x04 /* used compatibility mode */
|
|
||||||
#define ACORE 0x08 /* dumped core */
|
|
||||||
#define AXSIG 0x10 /* killed by a signal */
|
|
||||||
char ac_flag; /* accounting flags */
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 1/AHZ is the granularity of the data encoded in the comp_t fields.
|
* Accounting structure version 2 (current).
|
||||||
* This is not necessarily equal to hz.
|
* The first byte is always zero.
|
||||||
|
* Time units are microseconds.
|
||||||
*/
|
*/
|
||||||
#define AHZ 64
|
|
||||||
|
struct acctv2 {
|
||||||
|
uint8_t ac_zero; /* zero identifies new version */
|
||||||
|
uint8_t ac_version; /* record version number */
|
||||||
|
uint16_t ac_len; /* record length */
|
||||||
|
|
||||||
|
char ac_comm[AC_COMM_LEN]; /* command name */
|
||||||
|
float ac_utime; /* user time */
|
||||||
|
float ac_stime; /* system time */
|
||||||
|
float ac_etime; /* elapsed time */
|
||||||
|
time_t ac_btime; /* starting time */
|
||||||
|
uid_t ac_uid; /* user id */
|
||||||
|
gid_t ac_gid; /* group id */
|
||||||
|
float ac_mem; /* average memory usage */
|
||||||
|
float ac_io; /* count of IO blocks */
|
||||||
|
__dev_t ac_tty; /* controlling tty */
|
||||||
|
|
||||||
|
uint16_t ac_len2; /* record length */
|
||||||
|
union {
|
||||||
|
__dev_t ac_align; /* force v1 compatible alignment */
|
||||||
|
|
||||||
|
#define AFORK 0x01 /* forked but not exec'ed */
|
||||||
|
/* ASU is no longer supported */
|
||||||
|
#define ASU 0x02 /* used super-user permissions */
|
||||||
|
#define ACOMPAT 0x04 /* used compatibility mode */
|
||||||
|
#define ACORE 0x08 /* dumped core */
|
||||||
|
#define AXSIG 0x10 /* killed by a signal */
|
||||||
|
#define ANVER 0x20 /* new record version */
|
||||||
|
|
||||||
|
uint8_t ac_flag; /* accounting flags */
|
||||||
|
} ac_trailer;
|
||||||
|
|
||||||
|
#define ac_flagx ac_trailer.ac_flag
|
||||||
|
};
|
||||||
.Ed
|
.Ed
|
||||||
.Pp
|
.Pp
|
||||||
If a terminated process was created by an
|
If a terminated process was created by an
|
||||||
@ -100,7 +109,10 @@ and
|
|||||||
.Dv ASIG .
|
.Dv ASIG .
|
||||||
.Dv ASU
|
.Dv ASU
|
||||||
is no longer supported.
|
is no longer supported.
|
||||||
|
.Dv ANVER
|
||||||
|
is always set in the above structure.
|
||||||
.Sh SEE ALSO
|
.Sh SEE ALSO
|
||||||
|
.Xr lastcomm 1 ,
|
||||||
.Xr acct 2 ,
|
.Xr acct 2 ,
|
||||||
.Xr execve 2 ,
|
.Xr execve 2 ,
|
||||||
.Xr sa 8
|
.Xr sa 8
|
||||||
@ -109,3 +121,11 @@ A
|
|||||||
.Nm
|
.Nm
|
||||||
file format appeared in
|
file format appeared in
|
||||||
.At v7 .
|
.At v7 .
|
||||||
|
The current record format was introduced on May 2007.
|
||||||
|
It is backwards compatible with the previous format,
|
||||||
|
which is still documented in
|
||||||
|
.In sys/acct.h
|
||||||
|
and supported by
|
||||||
|
.Xr lastcomm 1
|
||||||
|
and
|
||||||
|
.Xr sa 8 .
|
||||||
|
@ -101,18 +101,26 @@ __FBSDID("$FreeBSD$");
|
|||||||
* Leffler, et al.: The Design and Implementation of the 4.3BSD
|
* Leffler, et al.: The Design and Implementation of the 4.3BSD
|
||||||
* UNIX Operating System (Addison Welley, 1989)
|
* UNIX Operating System (Addison Welley, 1989)
|
||||||
* on pages 62-63.
|
* on pages 62-63.
|
||||||
|
* On May 2007 the historic 3 bits base 8 exponent, 13 bit fraction
|
||||||
|
* compt_t representation described in the above reference was replaced
|
||||||
|
* with that of IEEE-754 floats.
|
||||||
*
|
*
|
||||||
* Arguably, to simplify accounting operations, this mechanism should
|
* Arguably, to simplify accounting operations, this mechanism should
|
||||||
* be replaced by one in which an accounting log file (similar to /dev/klog)
|
* be replaced by one in which an accounting log file (similar to /dev/klog)
|
||||||
* is read by a user process, etc. However, that has its own problems.
|
* is read by a user process, etc. However, that has its own problems.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* Floating point definitions from <float.h>. */
|
||||||
|
#define FLT_MANT_DIG 24 /* p */
|
||||||
|
#define FLT_MAX_EXP 128 /* emax */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Internal accounting functions.
|
* Internal accounting functions.
|
||||||
* The former's operation is described in Leffler, et al., and the latter
|
* The former's operation is described in Leffler, et al., and the latter
|
||||||
* was provided by UCB with the 4.4BSD-Lite release
|
* was provided by UCB with the 4.4BSD-Lite release
|
||||||
*/
|
*/
|
||||||
static comp_t encode_comp_t(u_long, u_long);
|
static uint32_t encode_timeval(struct timeval);
|
||||||
|
static uint32_t encode_long(long);
|
||||||
static void acctwatch(void);
|
static void acctwatch(void);
|
||||||
static void acct_thread(void *);
|
static void acct_thread(void *);
|
||||||
static int acct_disable(struct thread *);
|
static int acct_disable(struct thread *);
|
||||||
@ -325,7 +333,7 @@ acct_disable(struct thread *td)
|
|||||||
int
|
int
|
||||||
acct_process(struct thread *td)
|
acct_process(struct thread *td)
|
||||||
{
|
{
|
||||||
struct acct acct;
|
struct acctv2 acct;
|
||||||
struct timeval ut, st, tmp;
|
struct timeval ut, st, tmp;
|
||||||
struct plimit *newlim, *oldlim;
|
struct plimit *newlim, *oldlim;
|
||||||
struct proc *p;
|
struct proc *p;
|
||||||
@ -363,8 +371,8 @@ acct_process(struct thread *td)
|
|||||||
|
|
||||||
/* (2) The amount of user and system time that was used */
|
/* (2) The amount of user and system time that was used */
|
||||||
calcru(p, &ut, &st);
|
calcru(p, &ut, &st);
|
||||||
acct.ac_utime = encode_comp_t(ut.tv_sec, ut.tv_usec);
|
acct.ac_utime = encode_timeval(ut);
|
||||||
acct.ac_stime = encode_comp_t(st.tv_sec, st.tv_usec);
|
acct.ac_stime = encode_timeval(st);
|
||||||
|
|
||||||
/* (3) The elapsed time the command ran (and its starting time) */
|
/* (3) The elapsed time the command ran (and its starting time) */
|
||||||
tmp = boottime;
|
tmp = boottime;
|
||||||
@ -372,20 +380,22 @@ acct_process(struct thread *td)
|
|||||||
acct.ac_btime = tmp.tv_sec;
|
acct.ac_btime = tmp.tv_sec;
|
||||||
microuptime(&tmp);
|
microuptime(&tmp);
|
||||||
timevalsub(&tmp, &p->p_stats->p_start);
|
timevalsub(&tmp, &p->p_stats->p_start);
|
||||||
acct.ac_etime = encode_comp_t(tmp.tv_sec, tmp.tv_usec);
|
acct.ac_etime = encode_timeval(tmp);
|
||||||
|
|
||||||
/* (4) The average amount of memory used */
|
/* (4) The average amount of memory used */
|
||||||
r = &p->p_stats->p_ru;
|
r = &p->p_stats->p_ru;
|
||||||
tmp = ut;
|
tmp = ut;
|
||||||
timevaladd(&tmp, &st);
|
timevaladd(&tmp, &st);
|
||||||
|
/* Convert tmp (i.e. u + s) into hz units to match ru_i*. */
|
||||||
t = tmp.tv_sec * hz + tmp.tv_usec / tick;
|
t = tmp.tv_sec * hz + tmp.tv_usec / tick;
|
||||||
if (t)
|
if (t)
|
||||||
acct.ac_mem = (r->ru_ixrss + r->ru_idrss + r->ru_isrss) / t;
|
acct.ac_mem = encode_long((r->ru_ixrss + r->ru_idrss +
|
||||||
|
+ r->ru_isrss) / t);
|
||||||
else
|
else
|
||||||
acct.ac_mem = 0;
|
acct.ac_mem = 0;
|
||||||
|
|
||||||
/* (5) The number of disk I/O operations done */
|
/* (5) The number of disk I/O operations done */
|
||||||
acct.ac_io = encode_comp_t(r->ru_inblock + r->ru_oublock, 0);
|
acct.ac_io = encode_long(r->ru_inblock + r->ru_oublock);
|
||||||
|
|
||||||
/* (6) The UID and GID of the process */
|
/* (6) The UID and GID of the process */
|
||||||
acct.ac_uid = p->p_ucred->cr_ruid;
|
acct.ac_uid = p->p_ucred->cr_ruid;
|
||||||
@ -400,9 +410,15 @@ acct_process(struct thread *td)
|
|||||||
SESS_UNLOCK(p->p_session);
|
SESS_UNLOCK(p->p_session);
|
||||||
|
|
||||||
/* (8) The boolean flags that tell how the process terminated, etc. */
|
/* (8) The boolean flags that tell how the process terminated, etc. */
|
||||||
acct.ac_flag = p->p_acflag;
|
acct.ac_flagx = p->p_acflag;
|
||||||
PROC_UNLOCK(p);
|
PROC_UNLOCK(p);
|
||||||
|
|
||||||
|
/* Setup ancillary structure fields. */
|
||||||
|
acct.ac_flagx |= ANVER;
|
||||||
|
acct.ac_zero = 0;
|
||||||
|
acct.ac_version = 2;
|
||||||
|
acct.ac_len = acct.ac_len2 = sizeof(acct);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Eliminate any file size rlimit.
|
* Eliminate any file size rlimit.
|
||||||
*/
|
*/
|
||||||
@ -428,44 +444,102 @@ acct_process(struct thread *td)
|
|||||||
return (ret);
|
return (ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* FLOAT_CONVERSION_START (Regression testing; don't remove this line.) */
|
||||||
|
|
||||||
|
/* Convert timevals and longs into IEEE-754 bit patterns. */
|
||||||
|
|
||||||
|
/* Mantissa mask (MSB is implied, so subtract 1). */
|
||||||
|
#define MANT_MASK ((1 << (FLT_MANT_DIG - 1)) - 1)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Encode_comp_t converts from ticks in seconds and microseconds
|
* We calculate integer values to a precision of approximately
|
||||||
* to ticks in 1/AHZ seconds. The encoding is described in
|
* 28 bits.
|
||||||
* Leffler, et al., on page 63.
|
* This is high-enough precision to fill the 24 float bits
|
||||||
|
* and low-enough to avoid overflowing the 32 int bits.
|
||||||
*/
|
*/
|
||||||
|
#define CALC_BITS 28
|
||||||
|
|
||||||
#define MANTSIZE 13 /* 13 bit mantissa. */
|
/* log_2(1000000). */
|
||||||
#define EXPSIZE 3 /* Base 8 (3 bit) exponent. */
|
#define LOG2_1M 20
|
||||||
#define MAXFRACT ((1 << MANTSIZE) - 1) /* Maximum fractional value. */
|
|
||||||
|
|
||||||
static comp_t
|
/*
|
||||||
encode_comp_t(u_long s, u_long us)
|
* Convert the elements of a timeval into a 32-bit word holding
|
||||||
|
* the bits of a IEEE-754 float.
|
||||||
|
* The float value represents the timeval's value in microsecond units.
|
||||||
|
*/
|
||||||
|
static uint32_t
|
||||||
|
encode_timeval(struct timeval tv)
|
||||||
{
|
{
|
||||||
int exp, rnd;
|
int log2_s;
|
||||||
|
int val, exp; /* Unnormalized value and exponent */
|
||||||
|
int norm_exp; /* Normalized exponent */
|
||||||
|
int shift;
|
||||||
|
|
||||||
exp = 0;
|
/*
|
||||||
rnd = 0;
|
* First calculate value and exponent to about CALC_BITS precision.
|
||||||
s *= AHZ;
|
* Note that the following conditionals have been ordered so that
|
||||||
s += us / (1000000 / AHZ); /* Maximize precision. */
|
* the most common cases appear first.
|
||||||
|
*/
|
||||||
while (s > MAXFRACT) {
|
if (tv.tv_sec == 0) {
|
||||||
rnd = s & (1 << (EXPSIZE - 1)); /* Round up? */
|
if (tv.tv_usec == 0)
|
||||||
s >>= EXPSIZE; /* Base 8 exponent == 3 bit shift. */
|
return (0);
|
||||||
exp++;
|
exp = 0;
|
||||||
|
val = tv.tv_usec;
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* Calculate the value to a precision of approximately
|
||||||
|
* CALC_BITS.
|
||||||
|
*/
|
||||||
|
log2_s = fls(tv.tv_sec) - 1;
|
||||||
|
if (log2_s + LOG2_1M < CALC_BITS) {
|
||||||
|
exp = 0;
|
||||||
|
val = 1000000 * tv.tv_sec + tv.tv_usec;
|
||||||
|
} else {
|
||||||
|
exp = log2_s + LOG2_1M - CALC_BITS;
|
||||||
|
val = (unsigned int)(((u_int64_t)1000000 * tv.tv_sec +
|
||||||
|
tv.tv_usec) >> exp);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
/* Now normalize and pack the value into an IEEE-754 float. */
|
||||||
/* If we need to round up, do it (and handle overflow correctly). */
|
norm_exp = fls(val) - 1;
|
||||||
if (rnd && (++s > MAXFRACT)) {
|
shift = FLT_MANT_DIG - norm_exp - 1;
|
||||||
s >>= EXPSIZE;
|
#ifdef ACCT_DEBUG
|
||||||
exp++;
|
printf("val=%d exp=%d shift=%d log2(val)=%d\n",
|
||||||
}
|
val, exp, shift, norm_exp);
|
||||||
|
printf("exp=%x mant=%x\n", FLT_MAX_EXP - 1 + exp + norm_exp,
|
||||||
/* Clean it up and polish it off. */
|
((shift > 0 ? (val << shift) : (val >> -shift)) & MANT_MASK));
|
||||||
exp <<= MANTSIZE; /* Shift the exponent into place */
|
#endif
|
||||||
exp += s; /* and add on the mantissa. */
|
return (((FLT_MAX_EXP - 1 + exp + norm_exp) << (FLT_MANT_DIG - 1)) |
|
||||||
return (exp);
|
((shift > 0 ? val << shift : val >> -shift) & MANT_MASK));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convert a non-negative long value into the bit pattern of
|
||||||
|
* an IEEE-754 float value.
|
||||||
|
*/
|
||||||
|
static uint32_t
|
||||||
|
encode_long(long val)
|
||||||
|
{
|
||||||
|
int norm_exp; /* Normalized exponent */
|
||||||
|
int shift;
|
||||||
|
|
||||||
|
KASSERT(val >= 0, ("encode_long: -ve value %ld", val));
|
||||||
|
if (val == 0)
|
||||||
|
return (0);
|
||||||
|
norm_exp = fls(val) - 1;
|
||||||
|
shift = FLT_MANT_DIG - norm_exp - 1;
|
||||||
|
#ifdef ACCT_DEBUG
|
||||||
|
printf("val=%d shift=%d log2(val)=%d\n",
|
||||||
|
val, shift, norm_exp);
|
||||||
|
printf("exp=%x mant=%x\n", FLT_MAX_EXP - 1 + exp + norm_exp,
|
||||||
|
((shift > 0 ? (val << shift) : (val >> -shift)) & MANT_MASK));
|
||||||
|
#endif
|
||||||
|
return (((FLT_MAX_EXP - 1 + norm_exp) << (FLT_MANT_DIG - 1)) |
|
||||||
|
((shift > 0 ? val << shift : val >> -shift) & MANT_MASK));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FLOAT_CONVERSION_END (Regression testing; don't remove this line.) */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Periodically check the filesystem to see if accounting
|
* Periodically check the filesystem to see if accounting
|
||||||
* should be turned on or off. Beware the case where the vnode
|
* should be turned on or off. Beware the case where the vnode
|
||||||
|
@ -38,45 +38,88 @@
|
|||||||
#ifndef _SYS_ACCT_H_
|
#ifndef _SYS_ACCT_H_
|
||||||
#define _SYS_ACCT_H_
|
#define _SYS_ACCT_H_
|
||||||
|
|
||||||
/*
|
#ifdef _KERNEL
|
||||||
* Accounting structures; these use a comp_t type which is a 3 bits base 8
|
#define float uint32_t
|
||||||
* exponent, 13 bit fraction ``floating point'' number. Units are 1/AHZ
|
#endif
|
||||||
* seconds.
|
|
||||||
*/
|
|
||||||
typedef u_int16_t comp_t;
|
|
||||||
|
|
||||||
#define AC_COMM_LEN 16
|
#define AC_COMM_LEN 16
|
||||||
struct acct {
|
|
||||||
|
/*
|
||||||
|
* Accounting structure version 2 (current).
|
||||||
|
* The first byte is always zero.
|
||||||
|
* Time units are microseconds.
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct acctv2 {
|
||||||
|
uint8_t ac_zero; /* zero identifies new version */
|
||||||
|
uint8_t ac_version; /* record version number */
|
||||||
|
uint16_t ac_len; /* record length */
|
||||||
|
|
||||||
char ac_comm[AC_COMM_LEN]; /* command name */
|
char ac_comm[AC_COMM_LEN]; /* command name */
|
||||||
comp_t ac_utime; /* user time */
|
float ac_utime; /* user time */
|
||||||
comp_t ac_stime; /* system time */
|
float ac_stime; /* system time */
|
||||||
comp_t ac_etime; /* elapsed time */
|
float ac_etime; /* elapsed time */
|
||||||
time_t ac_btime; /* starting time */
|
time_t ac_btime; /* starting time */
|
||||||
uid_t ac_uid; /* user id */
|
uid_t ac_uid; /* user id */
|
||||||
gid_t ac_gid; /* group id */
|
gid_t ac_gid; /* group id */
|
||||||
u_int16_t ac_mem; /* average memory usage */
|
float ac_mem; /* average memory usage */
|
||||||
comp_t ac_io; /* count of IO blocks */
|
float ac_io; /* count of IO blocks */
|
||||||
__dev_t ac_tty; /* controlling tty */
|
__dev_t ac_tty; /* controlling tty */
|
||||||
|
|
||||||
|
uint16_t ac_len2; /* record length */
|
||||||
|
union {
|
||||||
|
__dev_t ac_align; /* force v1 compatible alignment */
|
||||||
|
|
||||||
#define AFORK 0x01 /* forked but not exec'ed */
|
#define AFORK 0x01 /* forked but not exec'ed */
|
||||||
/* ASU is no longer supported */
|
/* ASU is no longer supported */
|
||||||
#define ASU 0x02 /* used super-user permissions */
|
#define ASU 0x02 /* used super-user permissions */
|
||||||
#define ACOMPAT 0x04 /* used compatibility mode */
|
#define ACOMPAT 0x04 /* used compatibility mode */
|
||||||
#define ACORE 0x08 /* dumped core */
|
#define ACORE 0x08 /* dumped core */
|
||||||
#define AXSIG 0x10 /* killed by a signal */
|
#define AXSIG 0x10 /* killed by a signal */
|
||||||
u_int8_t ac_flag; /* accounting flags */
|
#define ANVER 0x20 /* new record version */
|
||||||
|
|
||||||
|
uint8_t ac_flag; /* accounting flags */
|
||||||
|
} ac_trailer;
|
||||||
|
|
||||||
|
#define ac_flagx ac_trailer.ac_flag
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Legacy accounting structure (rev. 1.5-1.18).
|
||||||
|
* The first byte is always non-zero.
|
||||||
|
* Some fields use a comp_t type which is a 3 bits base 8
|
||||||
|
* exponent, 13 bit fraction ``floating point'' number.
|
||||||
|
* Units are 1/AHZV1 seconds.
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef uint16_t comp_t;
|
||||||
|
|
||||||
|
struct acctv1 {
|
||||||
|
char ac_comm[AC_COMM_LEN]; /* command name */
|
||||||
|
comp_t ac_utime; /* user time */
|
||||||
|
comp_t ac_stime; /* system time */
|
||||||
|
comp_t ac_etime; /* elapsed time */
|
||||||
|
time_t ac_btime; /* starting time */
|
||||||
|
uid_t ac_uid; /* user id */
|
||||||
|
gid_t ac_gid; /* group id */
|
||||||
|
uint16_t ac_mem; /* average memory usage */
|
||||||
|
comp_t ac_io; /* count of IO blocks */
|
||||||
|
__dev_t ac_tty; /* controlling tty */
|
||||||
|
uint8_t ac_flag; /* accounting flags */
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 1/AHZ is the granularity of the data encoded in the comp_t fields.
|
* 1/AHZV1 is the granularity of the data encoded in the comp_t fields.
|
||||||
* This is not necessarily equal to hz.
|
* This is not necessarily equal to hz.
|
||||||
*/
|
*/
|
||||||
#define AHZ 64
|
#define AHZV1 64
|
||||||
|
|
||||||
#ifdef _KERNEL
|
#ifdef _KERNEL
|
||||||
struct thread;
|
struct thread;
|
||||||
|
|
||||||
int acct_process(struct thread *td);
|
int acct_process(struct thread *td);
|
||||||
|
#undef float
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* !_SYS_ACCT_H_ */
|
#endif /* !_SYS_ACCT_H_ */
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
# $FreeBSD$
|
# $FreeBSD$
|
||||||
|
|
||||||
PROG= lastcomm
|
PROG= lastcomm
|
||||||
|
SRCS= lastcomm.c readrec.c
|
||||||
WARNS?= 6
|
WARNS?= 6
|
||||||
|
|
||||||
.include <bsd.prog.mk>
|
.include <bsd.prog.mk>
|
||||||
|
@ -51,6 +51,7 @@ __FBSDID("$FreeBSD$");
|
|||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <err.h>
|
#include <err.h>
|
||||||
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <grp.h>
|
#include <grp.h>
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
@ -66,7 +67,9 @@ __FBSDID("$FreeBSD$");
|
|||||||
time_t expand(u_int);
|
time_t expand(u_int);
|
||||||
char *flagbits(int);
|
char *flagbits(int);
|
||||||
const char *getdev(dev_t);
|
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);
|
static void usage(void);
|
||||||
|
|
||||||
#define AC_UTIME 1 /* user */
|
#define AC_UTIME 1 /* user */
|
||||||
@ -77,18 +80,15 @@ static void usage(void);
|
|||||||
#define AC_BTIME 16 /* starting time */
|
#define AC_BTIME 16 /* starting time */
|
||||||
#define AC_FTIME 32 /* exit time (starting time + elapsed time )*/
|
#define AC_FTIME 32 /* exit time (starting time + elapsed time )*/
|
||||||
|
|
||||||
#define AC_HZ ((double)AHZ)
|
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char *argv[])
|
main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
|
struct acctv2 ab;
|
||||||
char *p;
|
char *p;
|
||||||
struct acct ab;
|
|
||||||
struct stat sb;
|
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
off_t size;
|
int (*readrec)(FILE *f, struct acctv2 *av2);
|
||||||
time_t t;
|
time_t t;
|
||||||
int ch;
|
int ch, rv;
|
||||||
const char *acctfile;
|
const char *acctfile;
|
||||||
int flags = 0;
|
int flags = 0;
|
||||||
|
|
||||||
@ -135,78 +135,51 @@ main(int argc, char *argv[])
|
|||||||
|
|
||||||
if (strcmp(acctfile, "-") == 0) {
|
if (strcmp(acctfile, "-") == 0) {
|
||||||
fp = stdin;
|
fp = stdin;
|
||||||
size = sizeof(struct acct); /* Always one more to read. */
|
readrec = readrec_forward;
|
||||||
} else {
|
} else {
|
||||||
/* Open the file. */
|
/* Open the file. */
|
||||||
if ((fp = fopen(acctfile, "r")) == NULL ||
|
if ((fp = fopen(acctfile, "r")) == NULL)
|
||||||
fstat(fileno(fp), &sb))
|
|
||||||
err(1, "could not open %s", acctfile);
|
err(1, "could not open %s", acctfile);
|
||||||
|
if (fseek(fp, 0l, SEEK_END) == -1)
|
||||||
/*
|
err(1, "seek to end of %s failed", acctfile);
|
||||||
* Round off to integral number of accounting records,
|
readrec = readrec_backward;
|
||||||
* 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
while ((rv = readrec(fp, &ab)) == 1) {
|
||||||
int rv;
|
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))
|
if (*argv && !requested(argv, &ab))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
(void)printf("%-*.*s %-7s %-*s %-*s",
|
(void)printf("%-*.*s %-7s %-*s %-*s",
|
||||||
AC_COMM_LEN, AC_COMM_LEN, ab.ac_comm,
|
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_NAMESIZE, user_from_uid(ab.ac_uid, 0),
|
||||||
UT_LINESIZE, getdev(ab.ac_tty));
|
UT_LINESIZE, getdev(ab.ac_tty));
|
||||||
|
|
||||||
|
|
||||||
/* user + system time */
|
/* user + system time */
|
||||||
if (flags & AC_CTIME) {
|
if (flags & AC_CTIME) {
|
||||||
(void)printf(" %6.2f secs",
|
(void)printf(" %6.3f secs",
|
||||||
(expand(ab.ac_utime) +
|
(ab.ac_utime + ab.ac_stime) / 1000000);
|
||||||
expand(ab.ac_stime))/AC_HZ);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* usr time */
|
/* usr time */
|
||||||
if (flags & AC_UTIME) {
|
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 */
|
/* system time */
|
||||||
if (flags & AC_STIME) {
|
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 */
|
/* elapsed time */
|
||||||
if (flags & AC_ETIME) {
|
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 */
|
/* starting time */
|
||||||
@ -217,31 +190,19 @@ main(int argc, char *argv[])
|
|||||||
/* exit time (starting time + elapsed time )*/
|
/* exit time (starting time + elapsed time )*/
|
||||||
if (flags & AC_FTIME) {
|
if (flags & AC_FTIME) {
|
||||||
t = ab.ac_btime;
|
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));
|
(void)printf(" %.16s", ctime(&t));
|
||||||
}
|
}
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
}
|
||||||
|
if (rv == EOF)
|
||||||
|
err(1, "read record from %s failed", acctfile);
|
||||||
|
|
||||||
} while (size > 0);
|
|
||||||
if (fflush(stdout))
|
if (fflush(stdout))
|
||||||
err(1, "stdout");
|
err(1, "stdout");
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
time_t
|
|
||||||
expand(u_int t)
|
|
||||||
{
|
|
||||||
time_t nt;
|
|
||||||
|
|
||||||
nt = t & 017777;
|
|
||||||
t >>= 13;
|
|
||||||
while (t) {
|
|
||||||
t--;
|
|
||||||
nt <<= 3;
|
|
||||||
}
|
|
||||||
return (nt);
|
|
||||||
}
|
|
||||||
|
|
||||||
char *
|
char *
|
||||||
flagbits(int f)
|
flagbits(int f)
|
||||||
{
|
{
|
||||||
@ -261,7 +222,7 @@ flagbits(int f)
|
|||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
requested(char *argv[], struct acct *acp)
|
requested(char *argv[], struct acctv2 *acp)
|
||||||
{
|
{
|
||||||
const char *p;
|
const char *p;
|
||||||
|
|
||||||
|
231
usr.bin/lastcomm/readrec.c
Normal file
231
usr.bin/lastcomm/readrec.c
Normal file
@ -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);
|
||||||
|
}
|
||||||
|
}
|
@ -2,8 +2,10 @@
|
|||||||
|
|
||||||
PROG= sa
|
PROG= sa
|
||||||
MAN= sa.8
|
MAN= sa.8
|
||||||
SRCS= main.c pdb.c usrdb.c
|
SRCS= main.c db.c pdb.c usrdb.c readrec.c
|
||||||
|
|
||||||
WARNS?= 6
|
WARNS?= 6
|
||||||
|
|
||||||
|
.PATH: ${.CURDIR}/../../usr.bin/lastcomm
|
||||||
|
|
||||||
.include <bsd.prog.mk>
|
.include <bsd.prog.mk>
|
||||||
|
207
usr.sbin/sa/db.c
Normal file
207
usr.sbin/sa/db.c
Normal file
@ -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);
|
||||||
|
}
|
@ -36,32 +36,41 @@
|
|||||||
|
|
||||||
/* structures */
|
/* structures */
|
||||||
|
|
||||||
|
/* All times are stored in 1e-6s units. */
|
||||||
|
|
||||||
struct cmdinfo {
|
struct cmdinfo {
|
||||||
char ci_comm[MAXCOMLEN+2]; /* command name (+ '*') */
|
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_calls; /* number of calls */
|
||||||
u_quad_t ci_etime; /* elapsed time */
|
double ci_etime; /* elapsed time */
|
||||||
u_quad_t ci_utime; /* user time */
|
double ci_utime; /* user time */
|
||||||
u_quad_t ci_stime; /* system time */
|
double ci_stime; /* system time */
|
||||||
u_quad_t ci_mem; /* memory use */
|
double ci_mem; /* memory use */
|
||||||
u_quad_t ci_io; /* number of disk i/o ops */
|
double ci_io; /* number of disk i/o ops */
|
||||||
u_int ci_flags; /* flags; see below */
|
u_int ci_flags; /* flags; see below */
|
||||||
};
|
};
|
||||||
#define CI_UNPRINTABLE 0x0001 /* unprintable chars in name */
|
#define CI_UNPRINTABLE 0x0001 /* unprintable chars in name */
|
||||||
|
|
||||||
struct userinfo {
|
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_calls; /* number of invocations */
|
||||||
u_quad_t ui_utime; /* user time */
|
double ui_utime; /* user time */
|
||||||
u_quad_t ui_stime; /* system time */
|
double ui_stime; /* system time */
|
||||||
u_quad_t ui_mem; /* memory use */
|
double ui_mem; /* memory use */
|
||||||
u_quad_t ui_io; /* number of disk i/o ops */
|
double ui_io; /* number of disk i/o ops */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* typedefs */
|
/* typedefs */
|
||||||
|
|
||||||
typedef int (*cmpf_t)(const DBT *, const DBT *);
|
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 */
|
/* external functions in pdb.c */
|
||||||
int pacct_init(void);
|
int pacct_init(void);
|
||||||
void pacct_destroy(void);
|
void pacct_destroy(void);
|
||||||
@ -69,6 +78,9 @@ int pacct_add(const struct cmdinfo *);
|
|||||||
int pacct_update(void);
|
int pacct_update(void);
|
||||||
void pacct_print(void);
|
void pacct_print(void);
|
||||||
|
|
||||||
|
/* external functions in readrec.c */
|
||||||
|
int readrec_forward(FILE *f, struct acctv2 *av2);
|
||||||
|
|
||||||
/* external functions in usrdb.c */
|
/* external functions in usrdb.c */
|
||||||
int usracct_init(void);
|
int usracct_init(void);
|
||||||
void usracct_destroy(void);
|
void usracct_destroy(void);
|
||||||
|
@ -46,6 +46,7 @@ __FBSDID("$FreeBSD$");
|
|||||||
#include <sys/acct.h>
|
#include <sys/acct.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <err.h>
|
#include <err.h>
|
||||||
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
@ -56,17 +57,16 @@ __FBSDID("$FreeBSD$");
|
|||||||
#include "extern.h"
|
#include "extern.h"
|
||||||
#include "pathnames.h"
|
#include "pathnames.h"
|
||||||
|
|
||||||
static int acct_load(const char *, int);
|
static FILE *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_comm(const char *, const char *);
|
static int cmp_usrsys(const DBT *, const DBT *);
|
||||||
static int cmp_usrsys(const DBT *, const DBT *);
|
static int cmp_avgusrsys(const DBT *, const DBT *);
|
||||||
static int cmp_avgusrsys(const DBT *, const DBT *);
|
static int cmp_dkio(const DBT *, const DBT *);
|
||||||
static int cmp_dkio(const DBT *, const DBT *);
|
static int cmp_avgdkio(const DBT *, const DBT *);
|
||||||
static int cmp_avgdkio(const DBT *, const DBT *);
|
static int cmp_cpumem(const DBT *, const DBT *);
|
||||||
static int cmp_cpumem(const DBT *, const DBT *);
|
static int cmp_avgcpumem(const DBT *, const DBT *);
|
||||||
static int cmp_avgcpumem(const DBT *, const DBT *);
|
static int cmp_calls(const DBT *, const DBT *);
|
||||||
static int cmp_calls(const DBT *, const DBT *);
|
static void usage(void);
|
||||||
static void usage(void);
|
|
||||||
|
|
||||||
int aflag, bflag, cflag, dflag, Dflag, fflag, iflag, jflag, kflag;
|
int aflag, bflag, cflag, dflag, Dflag, fflag, iflag, jflag, kflag;
|
||||||
int Kflag, lflag, mflag, qflag, rflag, sflag, tflag, uflag, vflag;
|
int Kflag, lflag, mflag, qflag, rflag, sflag, tflag, uflag, vflag;
|
||||||
@ -83,6 +83,7 @@ cmpf_t sa_cmp = cmp_usrsys;
|
|||||||
int
|
int
|
||||||
main(int argc, char **argv)
|
main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
|
FILE *f;
|
||||||
char pathacct[] = _PATH_ACCT;
|
char pathacct[] = _PATH_ACCT;
|
||||||
int ch, error = 0;
|
int ch, error = 0;
|
||||||
|
|
||||||
@ -210,14 +211,12 @@ main(int argc, char **argv)
|
|||||||
|
|
||||||
/* for each file specified */
|
/* for each file specified */
|
||||||
for (; argc > 0; argc--, argv++) {
|
for (; argc > 0; argc--, argv++) {
|
||||||
int fd;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* load the accounting data from the file.
|
* load the accounting data from the file.
|
||||||
* if it fails, go on to the next file.
|
* if it fails, go on to the next file.
|
||||||
*/
|
*/
|
||||||
fd = acct_load(argv[0], sflag);
|
f = acct_load(argv[0], sflag);
|
||||||
if (fd < 0)
|
if (f == NULL)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!uflag && sflag) {
|
if (!uflag && sflag) {
|
||||||
@ -248,7 +247,7 @@ main(int argc, char **argv)
|
|||||||
* the saved stats; better to underbill than overbill,
|
* the saved stats; better to underbill than overbill,
|
||||||
* but we want every accounting record intact.
|
* but we want every accounting record intact.
|
||||||
*/
|
*/
|
||||||
if (ftruncate(fd, 0) == -1) {
|
if (ftruncate(fileno(f), 0) == -1) {
|
||||||
warn("couldn't truncate %s", *argv);
|
warn("couldn't truncate %s", *argv);
|
||||||
error = 1;
|
error = 1;
|
||||||
}
|
}
|
||||||
@ -275,8 +274,8 @@ main(int argc, char **argv)
|
|||||||
/*
|
/*
|
||||||
* close the opened accounting file
|
* close the opened accounting file
|
||||||
*/
|
*/
|
||||||
if (close(fd) == -1) {
|
if (fclose(f) == EOF) {
|
||||||
warn("close %s", *argv);
|
warn("fclose %s", *argv);
|
||||||
error = 1;
|
error = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -308,21 +307,22 @@ usage()
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static FILE *
|
||||||
acct_load(const char *pn, int wr)
|
acct_load(const char *pn, int wr)
|
||||||
{
|
{
|
||||||
struct acct ac;
|
struct acctv2 ac;
|
||||||
struct cmdinfo ci;
|
struct cmdinfo ci;
|
||||||
ssize_t rv;
|
ssize_t rv;
|
||||||
int fd, i;
|
FILE *f;
|
||||||
|
int i;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* open the file
|
* open the file
|
||||||
*/
|
*/
|
||||||
fd = open(pn, wr ? O_RDWR : O_RDONLY, 0);
|
f = fopen(pn, wr ? "r+" : "r");
|
||||||
if (fd == -1) {
|
if (f == NULL) {
|
||||||
warn("open %s %s", pn, wr ? "for read/write" : "read-only");
|
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) {
|
while (1) {
|
||||||
/* get one accounting entry and punt if there's an error */
|
/* get one accounting entry and punt if there's an error */
|
||||||
rv = read(fd, &ac, sizeof(struct acct));
|
rv = readrec_forward(f, &ac);
|
||||||
if (rv == -1)
|
if (rv != 1) {
|
||||||
warn("error reading %s", pn);
|
if (rv == EOF)
|
||||||
else if (rv > 0 && rv < (int)sizeof(struct acct))
|
warn("error reading %s", pn);
|
||||||
warnx("short read of accounting data in %s", pn);
|
|
||||||
if (rv != sizeof(struct acct))
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/* decode it */
|
/* decode it */
|
||||||
ci.ci_calls = 1;
|
ci.ci_calls = 1;
|
||||||
@ -351,15 +350,15 @@ acct_load(const char *pn, int wr)
|
|||||||
} else
|
} else
|
||||||
ci.ci_comm[i] = c;
|
ci.ci_comm[i] = c;
|
||||||
}
|
}
|
||||||
if (ac.ac_flag & AFORK)
|
if (ac.ac_flagx & AFORK)
|
||||||
ci.ci_comm[i++] = '*';
|
ci.ci_comm[i++] = '*';
|
||||||
ci.ci_comm[i++] = '\0';
|
ci.ci_comm[i++] = '\0';
|
||||||
ci.ci_etime = decode_comp_t(ac.ac_etime);
|
ci.ci_etime = ac.ac_etime;
|
||||||
ci.ci_utime = decode_comp_t(ac.ac_utime);
|
ci.ci_utime = ac.ac_utime;
|
||||||
ci.ci_stime = decode_comp_t(ac.ac_stime);
|
ci.ci_stime = ac.ac_stime;
|
||||||
ci.ci_uid = ac.ac_uid;
|
ci.ci_uid = ac.ac_uid;
|
||||||
ci.ci_mem = ac.ac_mem;
|
ci.ci_mem = ac.ac_mem;
|
||||||
ci.ci_io = decode_comp_t(ac.ac_io) / AHZ;
|
ci.ci_io = ac.ac_io;
|
||||||
|
|
||||||
if (!uflag) {
|
if (!uflag) {
|
||||||
/* and enter it into the usracct and pacct databases */
|
/* and enter it into the usracct and pacct databases */
|
||||||
@ -368,34 +367,15 @@ acct_load(const char *pn, int wr)
|
|||||||
if (sflag || (mflag && !qflag))
|
if (sflag || (mflag && !qflag))
|
||||||
usracct_add(&ci);
|
usracct_add(&ci);
|
||||||
} else if (!qflag)
|
} 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_uid,
|
||||||
(ci.ci_utime + ci.ci_stime) / (double) AHZ,
|
(ci.ci_utime + ci.ci_stime) / 1000000,
|
||||||
(uintmax_t)ci.ci_mem, (uintmax_t)ci.ci_io,
|
ci.ci_mem, ci.ci_io,
|
||||||
ci.ci_comm);
|
ci.ci_comm);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* finally, return the file descriptor for possible truncation */
|
/* Finally, return the file stream for possible truncation. */
|
||||||
return (fd);
|
return (f);
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* sort commands, doing the right thing in terms of reversals */
|
/* sort commands, doing the right thing in terms of reversals */
|
||||||
@ -415,7 +395,7 @@ static int
|
|||||||
cmp_usrsys(const DBT *d1, const DBT *d2)
|
cmp_usrsys(const DBT *d1, const DBT *d2)
|
||||||
{
|
{
|
||||||
struct cmdinfo c1, c2;
|
struct cmdinfo c1, c2;
|
||||||
u_quad_t t1, t2;
|
double t1, t2;
|
||||||
|
|
||||||
memcpy(&c1, d1->data, sizeof(c1));
|
memcpy(&c1, d1->data, sizeof(c1));
|
||||||
memcpy(&c2, d2->data, sizeof(c2));
|
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(&c1, d1->data, sizeof(c1));
|
||||||
memcpy(&c2, d2->data, sizeof(c2));
|
memcpy(&c2, d2->data, sizeof(c2));
|
||||||
|
|
||||||
n1 = (double) c1.ci_io / (double) (c1.ci_calls ? c1.ci_calls : 1);
|
n1 = c1.ci_io / (double) (c1.ci_calls ? c1.ci_calls : 1);
|
||||||
n2 = (double) c2.ci_io / (double) (c2.ci_calls ? c2.ci_calls : 1);
|
n2 = c2.ci_io / (double) (c2.ci_calls ? c2.ci_calls : 1);
|
||||||
|
|
||||||
if (n1 < n2)
|
if (n1 < n2)
|
||||||
return -1;
|
return -1;
|
||||||
@ -515,7 +495,7 @@ static int
|
|||||||
cmp_avgcpumem(const DBT *d1, const DBT *d2)
|
cmp_avgcpumem(const DBT *d1, const DBT *d2)
|
||||||
{
|
{
|
||||||
struct cmdinfo c1, c2;
|
struct cmdinfo c1, c2;
|
||||||
u_quad_t t1, t2;
|
double t1, t2;
|
||||||
double n1, n2;
|
double n1, n2;
|
||||||
|
|
||||||
memcpy(&c1, d1->data, sizeof(c1));
|
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;
|
t1 = c1.ci_utime + c1.ci_stime;
|
||||||
t2 = c2.ci_utime + c2.ci_stime;
|
t2 = c2.ci_utime + c2.ci_stime;
|
||||||
|
|
||||||
n1 = (double) c1.ci_mem / (double) (t1 ? t1 : 1);
|
n1 = c1.ci_mem / (t1 ? t1 : 1);
|
||||||
n2 = (double) c2.ci_mem / (double) (t2 ? t2 : 1);
|
n2 = c2.ci_mem / (t2 ? t2 : 1);
|
||||||
|
|
||||||
if (n1 < n2)
|
if (n1 < n2)
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -36,6 +36,7 @@ __FBSDID("$FreeBSD$");
|
|||||||
#include <err.h>
|
#include <err.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -48,68 +49,61 @@ static void print_ci(const struct cmdinfo *, const struct cmdinfo *);
|
|||||||
|
|
||||||
static DB *pacct_db;
|
static DB *pacct_db;
|
||||||
|
|
||||||
|
/* 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)
|
||||||
|
{
|
||||||
|
struct cmdinfov1 civ1;
|
||||||
|
static struct cmdinfo civ2;
|
||||||
|
|
||||||
|
if (data->size != sizeof(civ1)) {
|
||||||
|
errno = EFTYPE;
|
||||||
|
return (-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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy pdb_file to in-memory pacct_db. */
|
||||||
int
|
int
|
||||||
pacct_init()
|
pacct_init()
|
||||||
{
|
{
|
||||||
DB *saved_pacct_db;
|
return (db_copy_in(&pacct_db, pdb_file, "process accounting",
|
||||||
int error;
|
NULL, v1_to_v2));
|
||||||
|
|
||||||
pacct_db = dbopen(NULL, O_RDWR, 0, DB_BTREE, NULL);
|
|
||||||
if (pacct_db == NULL)
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
out: if (error != 0)
|
|
||||||
pacct_destroy();
|
|
||||||
return (error);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
pacct_destroy()
|
pacct_destroy()
|
||||||
{
|
{
|
||||||
if (DB_CLOSE(pacct_db) < 0)
|
db_destroy(pacct_db, "process accounting");
|
||||||
warn("destroying process accounting stats");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
@ -154,52 +148,12 @@ pacct_add(const struct cmdinfo *ci)
|
|||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Copy in-memory pacct_db to pdb_file. */
|
||||||
int
|
int
|
||||||
pacct_update()
|
pacct_update()
|
||||||
{
|
{
|
||||||
DB *saved_pacct_db;
|
return (db_copy_out(pacct_db, pdb_file, "process accounting",
|
||||||
DBT key, data;
|
NULL));
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -330,7 +284,7 @@ print_ci(const struct cmdinfo *cip, const struct cmdinfo *totalcip)
|
|||||||
int uflow;
|
int uflow;
|
||||||
|
|
||||||
c = cip->ci_calls ? cip->ci_calls : 1;
|
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) {
|
if (t < 0.01) {
|
||||||
t = 0.01;
|
t = 0.01;
|
||||||
uflow = 1;
|
uflow = 1;
|
||||||
@ -347,26 +301,26 @@ print_ci(const struct cmdinfo *cip, const struct cmdinfo *totalcip)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (jflag)
|
if (jflag)
|
||||||
printf("%11.2fre ", cip->ci_etime / (double) (AHZ * c));
|
printf("%11.3fre ", cip->ci_etime / (1000000 * c));
|
||||||
else
|
else
|
||||||
printf("%11.2fre ", cip->ci_etime / (60.0 * AHZ));
|
printf("%11.3fre ", cip->ci_etime / (60.0 * 1000000));
|
||||||
if (cflag) {
|
if (cflag) {
|
||||||
if (cip != totalcip)
|
if (cip != totalcip)
|
||||||
printf(" %4.1f%% ", cip->ci_etime /
|
printf(" %4.1f%% ", cip->ci_etime /
|
||||||
(double)totalcip->ci_etime * 100);
|
totalcip->ci_etime * 100);
|
||||||
else
|
else
|
||||||
printf(" %4s ", "");
|
printf(" %4s ", "");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!lflag) {
|
if (!lflag) {
|
||||||
if (jflag)
|
if (jflag)
|
||||||
printf("%11.2fcp ", t / (double) cip->ci_calls);
|
printf("%11.3fcp ", t / (double) cip->ci_calls);
|
||||||
else
|
else
|
||||||
printf("%11.2fcp ", t / 60.0);
|
printf("%11.2fcp ", t / 60.0);
|
||||||
if (cflag) {
|
if (cflag) {
|
||||||
if (cip != totalcip)
|
if (cip != totalcip)
|
||||||
printf(" %4.1f%% ",
|
printf(" %4.1f%% ",
|
||||||
(double)(cip->ci_utime + cip->ci_stime) /
|
(cip->ci_utime + cip->ci_stime) /
|
||||||
(totalcip->ci_utime + totalcip->ci_stime) *
|
(totalcip->ci_utime + totalcip->ci_stime) *
|
||||||
100);
|
100);
|
||||||
else
|
else
|
||||||
@ -374,9 +328,9 @@ print_ci(const struct cmdinfo *cip, const struct cmdinfo *totalcip)
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (jflag)
|
if (jflag)
|
||||||
printf("%11.2fu ", cip->ci_utime / (double) (AHZ * c));
|
printf("%11.3fu ", cip->ci_utime / (1000000 * c));
|
||||||
else
|
else
|
||||||
printf("%11.2fu ", cip->ci_utime / (60.0 * AHZ));
|
printf("%11.2fu ", cip->ci_utime / (60.0 * 1000000));
|
||||||
if (cflag) {
|
if (cflag) {
|
||||||
if (cip != totalcip)
|
if (cip != totalcip)
|
||||||
printf(" %4.1f%% ", cip->ci_utime /
|
printf(" %4.1f%% ", cip->ci_utime /
|
||||||
@ -385,9 +339,9 @@ print_ci(const struct cmdinfo *cip, const struct cmdinfo *totalcip)
|
|||||||
printf(" %4s ", "");
|
printf(" %4s ", "");
|
||||||
}
|
}
|
||||||
if (jflag)
|
if (jflag)
|
||||||
printf("%11.2fs ", cip->ci_stime / (double) (AHZ * c));
|
printf("%11.3fs ", cip->ci_stime / (1000000 * c));
|
||||||
else
|
else
|
||||||
printf("%11.2fs ", cip->ci_stime / (60.0 * AHZ));
|
printf("%11.2fs ", cip->ci_stime / (60.0 * 1000000));
|
||||||
if (cflag) {
|
if (cflag) {
|
||||||
if (cip != totalcip)
|
if (cip != totalcip)
|
||||||
printf(" %4.1f%% ", cip->ci_stime /
|
printf(" %4.1f%% ", cip->ci_stime /
|
||||||
@ -401,18 +355,18 @@ print_ci(const struct cmdinfo *cip, const struct cmdinfo *totalcip)
|
|||||||
if (!uflow)
|
if (!uflow)
|
||||||
printf("%8.2fre/cp ",
|
printf("%8.2fre/cp ",
|
||||||
cip->ci_etime /
|
cip->ci_etime /
|
||||||
(double) (cip->ci_utime + cip->ci_stime));
|
(cip->ci_utime + cip->ci_stime));
|
||||||
else
|
else
|
||||||
printf("*ignore* ");
|
printf("*ignore* ");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Dflag)
|
if (Dflag)
|
||||||
printf("%10jutio ", (uintmax_t)cip->ci_io);
|
printf("%10.0fio ", cip->ci_io);
|
||||||
else
|
else
|
||||||
printf("%8.0favio ", cip->ci_io / c);
|
printf("%8.0favio ", cip->ci_io / c);
|
||||||
|
|
||||||
if (Kflag)
|
if (Kflag)
|
||||||
printf("%10juk*sec ", (uintmax_t)cip->ci_mem);
|
printf("%10.0fk*sec ", cip->ci_mem);
|
||||||
else
|
else
|
||||||
printf("%8.0fk ", cip->ci_mem / t);
|
printf("%8.0fk ", cip->ci_mem / t);
|
||||||
|
|
||||||
|
@ -49,74 +49,69 @@ static int uid_compare(const DBT *, const DBT *);
|
|||||||
|
|
||||||
static DB *usracct_db;
|
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
|
int
|
||||||
usracct_init()
|
usracct_init()
|
||||||
{
|
{
|
||||||
DB *saved_usracct_db;
|
|
||||||
BTREEINFO bti;
|
BTREEINFO bti;
|
||||||
int error;
|
|
||||||
|
|
||||||
bzero(&bti, sizeof bti);
|
bzero(&bti, sizeof bti);
|
||||||
bti.compare = uid_compare;
|
bti.compare = uid_compare;
|
||||||
|
|
||||||
usracct_db = dbopen(NULL, O_RDWR, 0, DB_BTREE, &bti);
|
return (db_copy_in(&usracct_db, usrdb_file, "user accounting",
|
||||||
if (usracct_db == NULL)
|
&bti, v1_to_v2));
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
usracct_destroy()
|
usracct_destroy()
|
||||||
{
|
{
|
||||||
if (DB_CLOSE(usracct_db) < 0)
|
db_destroy(usracct_db, "user accounting");
|
||||||
warn("destroying user accounting stats");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
@ -124,7 +119,7 @@ usracct_add(const struct cmdinfo *ci)
|
|||||||
{
|
{
|
||||||
DBT key, data;
|
DBT key, data;
|
||||||
struct userinfo newui;
|
struct userinfo newui;
|
||||||
u_long uid;
|
uid_t uid;
|
||||||
int rv;
|
int rv;
|
||||||
|
|
||||||
uid = ci->ci_uid;
|
uid = ci->ci_uid;
|
||||||
@ -133,13 +128,13 @@ usracct_add(const struct cmdinfo *ci)
|
|||||||
|
|
||||||
rv = DB_GET(usracct_db, &key, &data, 0);
|
rv = DB_GET(usracct_db, &key, &data, 0);
|
||||||
if (rv < 0) {
|
if (rv < 0) {
|
||||||
warn("get key %lu from user accounting stats", uid);
|
warn("get key %u from user accounting stats", uid);
|
||||||
return (-1);
|
return (-1);
|
||||||
} else if (rv == 0) { /* it's there; copy whole thing */
|
} else if (rv == 0) { /* it's there; copy whole thing */
|
||||||
/* add the old data to the new data */
|
/* add the old data to the new data */
|
||||||
bcopy(data.data, &newui, data.size);
|
bcopy(data.data, &newui, data.size);
|
||||||
if (newui.ui_uid != uid) {
|
if (newui.ui_uid != uid) {
|
||||||
warnx("key %lu != expected record number %lu",
|
warnx("key %u != expected record number %u",
|
||||||
newui.ui_uid, uid);
|
newui.ui_uid, uid);
|
||||||
warnx("inconsistent user accounting stats");
|
warnx("inconsistent user accounting stats");
|
||||||
return (-1);
|
return (-1);
|
||||||
@ -159,7 +154,7 @@ usracct_add(const struct cmdinfo *ci)
|
|||||||
data.size = sizeof newui;
|
data.size = sizeof newui;
|
||||||
rv = DB_PUT(usracct_db, &key, &data, 0);
|
rv = DB_PUT(usracct_db, &key, &data, 0);
|
||||||
if (rv < 0) {
|
if (rv < 0) {
|
||||||
warn("add key %lu to user accounting stats", uid);
|
warn("add key %u to user accounting stats", uid);
|
||||||
return (-1);
|
return (-1);
|
||||||
} else if (rv != 0) {
|
} else if (rv != 0) {
|
||||||
warnx("DB_PUT returned 1");
|
warnx("DB_PUT returned 1");
|
||||||
@ -169,56 +164,17 @@ usracct_add(const struct cmdinfo *ci)
|
|||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Copy in-memory usracct_db to usrdb_file. */
|
||||||
int
|
int
|
||||||
usracct_update()
|
usracct_update()
|
||||||
{
|
{
|
||||||
DB *saved_usracct_db;
|
|
||||||
DBT key, data;
|
|
||||||
BTREEINFO bti;
|
BTREEINFO bti;
|
||||||
int error, serr, nerr;
|
|
||||||
|
|
||||||
bzero(&bti, sizeof bti);
|
bzero(&bti, sizeof bti);
|
||||||
bti.compare = uid_compare;
|
bti.compare = uid_compare;
|
||||||
|
|
||||||
saved_usracct_db = dbopen(usrdb_file, O_RDWR|O_CREAT|O_TRUNC, 0644,
|
return (db_copy_out(usracct_db, usrdb_file, "user accounting",
|
||||||
DB_BTREE, &bti);
|
&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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -239,25 +195,24 @@ usracct_print()
|
|||||||
printf("%-*s %9ju ", MAXLOGNAME - 1,
|
printf("%-*s %9ju ", MAXLOGNAME - 1,
|
||||||
user_from_uid(ui->ui_uid, 0), (uintmax_t)ui->ui_calls);
|
user_from_uid(ui->ui_uid, 0), (uintmax_t)ui->ui_calls);
|
||||||
|
|
||||||
t = (double) (ui->ui_utime + ui->ui_stime) /
|
t = (ui->ui_utime + ui->ui_stime) / 1000000;
|
||||||
(double) AHZ;
|
if (t < 0.000001) /* kill divide by zero */
|
||||||
if (t < 0.0001) /* kill divide by zero */
|
t = 0.000001;
|
||||||
t = 0.0001;
|
|
||||||
|
|
||||||
printf("%12.2f%s ", t / 60.0, "cpu");
|
printf("%12.2f%s ", t / 60.0, "cpu");
|
||||||
|
|
||||||
/* ui->ui_calls is always != 0 */
|
/* ui->ui_calls is always != 0 */
|
||||||
if (dflag)
|
if (dflag)
|
||||||
printf("%12ju%s",
|
printf("%12.0f%s",
|
||||||
(uintmax_t)(ui->ui_io / ui->ui_calls), "avio");
|
ui->ui_io / ui->ui_calls, "avio");
|
||||||
else
|
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)
|
if (kflag)
|
||||||
printf("%12.0f%s", ui->ui_mem / t, "k");
|
printf("%12.0f%s", ui->ui_mem / t, "k");
|
||||||
else
|
else
|
||||||
printf("%12ju%s", (uintmax_t)ui->ui_mem, "k*sec");
|
printf("%12.0f%s", ui->ui_mem, "k*sec");
|
||||||
|
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
|
||||||
@ -270,7 +225,7 @@ usracct_print()
|
|||||||
static int
|
static int
|
||||||
uid_compare(const DBT *k1, const DBT *k2)
|
uid_compare(const DBT *k1, const DBT *k2)
|
||||||
{
|
{
|
||||||
u_long d1, d2;
|
uid_t d1, d2;
|
||||||
|
|
||||||
bcopy(k1->data, &d1, sizeof d1);
|
bcopy(k1->data, &d1, sizeof d1);
|
||||||
bcopy(k2->data, &d2, sizeof d2);
|
bcopy(k2->data, &d2, sizeof d2);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user