xref: /csrg-svn/sys/kern/kern_acct.c (revision 67655)
149587Sbostic /*-
263432Sbostic  * Copyright (c) 1982, 1986, 1989, 1993
363432Sbostic  *	The Regents of the University of California.  All rights reserved.
465771Sbostic  * (c) UNIX System Laboratories, Inc.
565771Sbostic  * All or some portions of this file are derived from material licensed
665771Sbostic  * to the University of California by American Telephone and Telegraph
765771Sbostic  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
865771Sbostic  * the permission of UNIX System Laboratories, Inc.
923365Smckusick  *
1049587Sbostic  * %sccs.include.proprietary.c%
1149587Sbostic  *
12*67655Smckusick  *	@(#)kern_acct.c	8.5 (Berkeley) 08/11/94
1323365Smckusick  */
1412788Ssam 
1556517Sbostic #include <sys/param.h>
1656517Sbostic #include <sys/systm.h>
1756517Sbostic #include <sys/namei.h>
1856517Sbostic #include <sys/resourcevar.h>
1956517Sbostic #include <sys/proc.h>
2056517Sbostic #include <sys/ioctl.h>
2156517Sbostic #include <sys/termios.h>
2256517Sbostic #include <sys/tty.h>
2356517Sbostic #include <sys/vnode.h>
2456517Sbostic #include <sys/mount.h>
2556517Sbostic #include <sys/kernel.h>
2656517Sbostic #include <sys/file.h>
2756517Sbostic #include <sys/acct.h>
2856517Sbostic #include <sys/syslog.h>
2912788Ssam 
3012788Ssam /*
3137728Smckusick  * Values associated with enabling and disabling accounting
3237728Smckusick  */
3337728Smckusick int	acctsuspend = 2;	/* stop accounting when < 2% free space left */
3437728Smckusick int	acctresume = 4;		/* resume when free space risen to > 4% */
3558149Smckusick int	acctchkfreq = 15;	/* frequency (in seconds) to check space */
3637728Smckusick 
3737728Smckusick /*
3812788Ssam  * SHOULD REPLACE THIS WITH A DRIVER THAT CAN BE READ TO SIMPLIFY.
3912788Ssam  */
4037728Smckusick struct	vnode *acctp;
4137728Smckusick struct	vnode *savacctp;
4212788Ssam 
4312788Ssam /*
4449671Smckusick  * Enable or disable process accounting.
4549671Smckusick  *
4649671Smckusick  * If a non-null filename is given, that file is used to store accounting
4749671Smckusick  * records on process exit. If a null filename is given process accounting
4849671Smckusick  * is suspended. If accounting is enabled, the system checks the amount
4949671Smckusick  * of freespace on the filesystem at timeval intervals. If the amount of
5049671Smckusick  * freespace is below acctsuspend percent, accounting is suspended. If
5149671Smckusick  * accounting has been suspended, and freespace rises above acctresume,
5249671Smckusick  * accounting is resumed.
5312788Ssam  */
5463431Sbostic struct acct_args {
5554919Storek 	char	*fname;
5654919Storek };
5763431Sbostic acct(p, uap, retval)
5843379Smckusick 	struct proc *p;
5963431Sbostic 	struct acct_args *uap;
6043379Smckusick 	int *retval;
6112788Ssam {
6237728Smckusick 	register struct vnode *vp;
6354789Storek 	extern void acctwatch __P((void *));
6437728Smckusick 	struct vnode *oacctp;
6543379Smckusick 	int error;
6647545Skarels 	struct nameidata nd;
6712788Ssam 
6847545Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
6944404Skarels 		return (error);
7037553Smckusick 	if (savacctp) {
7137553Smckusick 		acctp = savacctp;
7237553Smckusick 		savacctp = NULL;
7337553Smckusick 	}
7445055Smckusick 	if (uap->fname == NULL) {
7537728Smckusick 		if (vp = acctp) {
7637553Smckusick 			acctp = NULL;
7750107Smckusick 			error = vn_close(vp, FWRITE, p->p_ucred, p);
7854789Storek 			untimeout(acctwatch, NULL);
7912788Ssam 		}
8050107Smckusick 		return (error);
8112788Ssam 	}
8252307Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p);
8352307Smckusick 	if (error = vn_open(&nd, FWRITE, 0644))
8444404Skarels 		return (error);
8547545Skarels 	vp = nd.ni_vp;
8649916Smckusick 	VOP_UNLOCK(vp);
8737728Smckusick 	if (vp->v_type != VREG) {
8850107Smckusick 		(void) vn_close(vp, FWRITE, p->p_ucred, p);
8944404Skarels 		return (EACCES);
9037553Smckusick 	}
9137728Smckusick 	oacctp = acctp;
9237728Smckusick 	acctp = vp;
9337728Smckusick 	if (oacctp)
9450107Smckusick 		error = vn_close(oacctp, FWRITE, p->p_ucred, p);
9554789Storek 	acctwatch(NULL);
9650107Smckusick 	return (error);
9712788Ssam }
9812788Ssam 
9912788Ssam /*
10037728Smckusick  * Periodically check the file system to see if accounting
10167359Smckusick  * should be turned on or off. Beware the case where the vnode
10267359Smckusick  * has been vgone()'d out from underneath us, e.g. when the file
10367359Smckusick  * system containing the accounting file has been forcibly unmounted.
10412788Ssam  */
10554789Storek /* ARGSUSED */
10654789Storek void
10754789Storek acctwatch(a)
10854789Storek 	void *a;
10912788Ssam {
11037728Smckusick 	struct statfs sb;
11112788Ssam 
11212788Ssam 	if (savacctp) {
11367359Smckusick 		if (savacctp->v_type == VBAD) {
11467359Smckusick 			(void) vn_close(savacctp, FWRITE, NOCRED, NULL);
11567359Smckusick 			savacctp = NULL;
11667359Smckusick 			return;
11767359Smckusick 		}
11848021Smckusick 		(void)VFS_STATFS(savacctp->v_mount, &sb, (struct proc *)0);
11937728Smckusick 		if (sb.f_bavail > acctresume * sb.f_blocks / 100) {
12012788Ssam 			acctp = savacctp;
12112788Ssam 			savacctp = NULL;
12237728Smckusick 			log(LOG_NOTICE, "Accounting resumed\n");
12358149Smckusick 		}
12458149Smckusick 	} else {
12558149Smckusick 		if (acctp == NULL)
12637728Smckusick 			return;
12767359Smckusick 		if (acctp->v_type == VBAD) {
12867359Smckusick 			(void) vn_close(acctp, FWRITE, NOCRED, NULL);
12967359Smckusick 			acctp = NULL;
13067359Smckusick 			return;
13167359Smckusick 		}
13258149Smckusick 		(void)VFS_STATFS(acctp->v_mount, &sb, (struct proc *)0);
13358149Smckusick 		if (sb.f_bavail <= acctsuspend * sb.f_blocks / 100) {
13458149Smckusick 			savacctp = acctp;
13558149Smckusick 			acctp = NULL;
13658149Smckusick 			log(LOG_NOTICE, "Accounting suspended\n");
13712788Ssam 		}
13812788Ssam 	}
13958149Smckusick 	timeout(acctwatch, NULL, acctchkfreq * hz);
14037728Smckusick }
14137728Smckusick 
14237728Smckusick /*
14349671Smckusick  * This routine calculates an accounting record for a process and,
14449671Smckusick  * if accounting is enabled, writes it to the accounting file.
14537728Smckusick  */
14663431Sbostic acct_process(p)
14743379Smckusick 	register struct proc *p;
14837728Smckusick {
14937728Smckusick 	register struct rusage *ru;
15037728Smckusick 	struct vnode *vp;
15140803Smarc 	struct timeval t, ut, st;
15240803Smarc 	int i, s;
15337728Smckusick 	struct acct acctbuf;
15437728Smckusick 	register struct acct *ap = &acctbuf;
15537728Smckusick 
15637728Smckusick 	if ((vp = acctp) == NULL)
15743379Smckusick 		return (0);
15867359Smckusick 	if (vp->v_type == VBAD) {
15967359Smckusick 		(void) vn_close(vp, FWRITE, NOCRED, NULL);
16067359Smckusick 		acctp = NULL;
16167359Smckusick 		return (0);
16267359Smckusick 	}
16340803Smarc 	bcopy(p->p_comm, ap->ac_comm, sizeof(ap->ac_comm));
16447545Skarels 	ru = &p->p_stats->p_ru;
16554789Storek 	calcru(p, &ut, &st, NULL);
16640803Smarc 	s = splclock();
16716715Ssam 	t = time;
16840803Smarc 	splx(s);
16940803Smarc 	ap->ac_utime = compress(ut.tv_sec, ut.tv_usec);
17040803Smarc 	ap->ac_stime = compress(st.tv_sec, st.tv_usec);
17147545Skarels 	timevalsub(&t, &p->p_stats->p_start);
17216715Ssam 	ap->ac_etime = compress(t.tv_sec, t.tv_usec);
17347545Skarels 	ap->ac_btime = p->p_stats->p_start.tv_sec;
17447545Skarels 	ap->ac_uid = p->p_cred->p_ruid;
17547545Skarels 	ap->ac_gid = p->p_cred->p_rgid;
17640803Smarc 	t = st;
17740803Smarc 	timevaladd(&t, &ut);
17816719Skarels 	if (i = t.tv_sec * hz + t.tv_usec / tick)
17947545Skarels 		ap->ac_mem = (ru->ru_ixrss + ru->ru_idrss + ru->ru_isrss) / i;
18016715Ssam 	else
18116715Ssam 		ap->ac_mem = 0;
18226277Skarels 	ap->ac_io = compress(ru->ru_inblock + ru->ru_oublock, (long)0);
18364572Sbostic 	if (p->p_flag & P_CONTROLT && p->p_session->s_ttyp)
18440803Smarc 		ap->ac_tty = p->p_session->s_ttyp->t_dev;
18512788Ssam 	else
18612788Ssam 		ap->ac_tty = NODEV;
18747545Skarels 	ap->ac_flag = p->p_acflag;
188*67655Smckusick 	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
18948021Smckusick 	return (vn_rdwr(UIO_WRITE, vp, (caddr_t)ap, sizeof (acctbuf), (off_t)0,
19048021Smckusick 		UIO_SYSSPACE, IO_UNIT|IO_APPEND, p->p_ucred, (int *)0,
19148021Smckusick 		(struct proc *)0));
19212788Ssam }
19312788Ssam 
19412788Ssam /*
19512788Ssam  * Produce a pseudo-floating point representation
19612788Ssam  * with 3 bits base-8 exponent, 13 bits fraction.
19712788Ssam  */
19816715Ssam compress(t, ut)
19912788Ssam 	register long t;
20016715Ssam 	long ut;
20112788Ssam {
20212788Ssam 	register exp = 0, round = 0;
20312788Ssam 
20417501Skarels 	t = t * AHZ;  /* compiler will convert only this format to a shift */
20516715Ssam 	if (ut)
20617501Skarels 		t += ut / (1000000 / AHZ);
20712788Ssam 	while (t >= 8192) {
20812788Ssam 		exp++;
20912788Ssam 		round = t&04;
21012788Ssam 		t >>= 3;
21112788Ssam 	}
21212788Ssam 	if (round) {
21312788Ssam 		t++;
21412788Ssam 		if (t >= 8192) {
21512788Ssam 			t >>= 3;
21612788Ssam 			exp++;
21712788Ssam 		}
21812788Ssam 	}
21912788Ssam 	return ((exp<<13) + t);
22012788Ssam }
221