Source to kern/kern_acct.c
/*
* Copyright (c) 1982, 1986, 1989 Regents of the University of California.
* 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
*
* from: @(#)kern_acct.c 7.18 (Berkeley) 5/11/91
* kern_acct.c,v 1.9.2.1 1993/07/21 13:11:57 cgd Exp
*/
#include "param.h"
#include "systm.h"
#include "namei.h"
#include "resourcevar.h"
#include "proc.h"
#include "ioctl.h"
#include "termios.h"
#include "tty.h"
#include "vnode.h"
#include "mount.h"
#include "kernel.h"
#include "file.h"
#include "acct.h"
#include "syslog.h"
#include "acctbuf.h"
#ifdef ACCOUNTING
int acct_on;
#endif
/*
* Enable or disable process accounting.
*
* if "on" is nonzero, turn on accounting.
* recording of the actual accounting records is done by a user process
* reading /dev/acct.
*/
struct sysacct_args {
int acct_on;
};
/* ARGSUSED */
int
sysacct(p, uap, retval)
struct proc *p;
struct sysacct_args *uap;
int *retval;
{
#ifdef ACCOUNTING
int error;
if (error = suser(p->p_cred->pc_ucred, &p->p_acflag))
return (error);
acct_on = (*uap).acct_on;
return 0;
#else
/* accounting not compiled in */
return (ENOSYS);
#endif
}
#ifdef ACCOUNTING
/*
* This routine turns a number into a comp_t, which is a compressed
* floating point number. top 3 bits are an exponent (base 8), last 13 are
* the "fraction".
*
* this takes "units" and "microunits", because this is used for
* times and other things, too. comp_t's are in 1/AHZ units (why use
* a time unit for a general purpose thing?), so it's easiest to do
* conversion to those in here...
*/
#define COMP_T_FRACT_BITS 13 /* 13 bits of base */
#define MAX_COMP_T_FRACT (2<<COMP_T_FRACT_BITS - 1)
#define COMP_T_EXP_BASE_BITS 3 /* base-8 exponent */
#define SHIFT_COMP_T(exponent, mant) \
{ exponent++; mant >>= COMP_T_EXP_BASE_BITS; }
#define COMBINE_COMP_T(exponent, mant) \
(((exponent) << COMP_T_FRACT_BITS) + (mant))
comp_t
make_comp_t(long s, long us)
{
long m, e = 0, round = 0;
/* get mantissa to maximum precision -- hence "strange"
* division order
*/
m = s*AHZ + us/(1000000/AHZ);
/*
* convert as into a comp_t.
* as approx = comp_t_fract * 8^comp_t_exp
*/
while (m > MAX_COMP_T_FRACT) {
round = m & 0x04; /* shifting 3, is 2nd bit set? */
SHIFT_COMP_T(e, m);
}
/* if we round up, and overflow, shift it again */
if (round && (++m > MAX_COMP_T_FRACT))
SHIFT_COMP_T(e, m);
return COMBINE_COMP_T(e, m);
}
/*
* Write an accounting structure to the accounting log buffer
* mostly cloned from the system log routines...
*/
void
acct_write(struct acct *a)
{
struct acctbuf *abp;
#ifdef ACCT_DEBUG
char commbuf[sizeof(a->ac_comm)];
#endif
if (acctbufp == NULL)
acctbuf_init();
abp = acctbufp;
#ifdef ACCT_DEBUG
bcopy(a->ac_comm, commbuf, sizeof(a->ac_comm));
commbuf[sizeof(a->ac_comm)] = '\0';
printf("acct_write: command %s\n", a->ac_comm);
acctbuf_checkbuf("acct_write");
#endif
bcopy(a, &abp->recs[abp->ab_wind++], sizeof(struct acct));
if (abp->ab_wind < 0 || abp->ab_wind >= ACCT_NBRECS)
abp->ab_wind = 0;
if (abp->ab_wind == abp->ab_rind) {
#ifdef ACCT_DEBUG
printf("acct_write: accounting buffer overrun\n");
#endif
abp->ab_rind++;
if (abp->ab_rind < 0 || abp->ab_rind >= ACCT_NBRECS)
abp->ab_rind = 0;
}
acctwakeup();
}
/*
* This routine calculates an accounting record for a process and,
* if accounting is enabled, writes it to the accounting buffer.
*/
void
acct(p)
register struct proc *p;
{
struct acct a;
int s;
struct timeval t;
if (!acct_on)
return;
/* fill in accounting structure field by field.
* it really escapes me why some of these are declared
* as comp_t and some not... -- cgd
*/
bcopy(p->p_comm, a.ac_comm, sizeof a.ac_comm); /* command name */
a.ac_utime = make_comp_t(p->p_utime.tv_sec, p->p_utime.tv_usec);
/* user time */
a.ac_stime = make_comp_t(p->p_stime.tv_sec, p->p_stime.tv_usec);
/* system time */
s = splclock();
t = time; /* get the current time, so we can subtract */
splx(s);
timevalsub(&t, &p->p_stats->p_start);
a.ac_etime = make_comp_t(t.tv_sec, t.tv_usec); /* elapsed time */
a.ac_btime = p->p_stats->p_start.tv_sec; /* starting time */
a.ac_uid = p->p_cred->p_ruid; /* user id */
a.ac_gid = p->p_cred->p_rgid; /* group id */
a.ac_mem = 0; /* XXX */ /* average memory usage */
a.ac_io = 0; /* XXX */ /* count of IO blocks */
/* if we've got a tty, and it's controlling, note it */
if (p->p_session->s_ttyp && p->p_flag & SCTTY)
a.ac_tty = p->p_session->s_ttyp->t_dev;
else
a.ac_tty = NODEV;
a.ac_flag = p->p_acflag; /* accounting flags */
acct_write(&a);
return;
}
#endif /* ACCOUNTING */