Source to kern/kern_acct.c


Enter a symbol's name here to quickly find it.

/*
 * 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 */