xref: /csrg-svn/sys/kern/kern_acct.c (revision 43379)
123365Smckusick /*
237728Smckusick  * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
339481Smckusick  * All rights reserved.  The Berkeley software License Agreement
439481Smckusick  * specifies the terms and conditions for redistribution.
523365Smckusick  *
6*43379Smckusick  *	@(#)kern_acct.c	7.11 (Berkeley) 06/21/90
723365Smckusick  */
812788Ssam 
917088Sbloom #include "param.h"
1017088Sbloom #include "systm.h"
1138931Skarels #include "time.h"
1238931Skarels #include "proc.h"
13*43379Smckusick #include "ioctl.h"
14*43379Smckusick #include "termios.h"
15*43379Smckusick #include "tty.h"
16*43379Smckusick #undef RETURN
17*43379Smckusick #include "syscontext.h"
1837728Smckusick #include "vnode.h"
1937728Smckusick #include "mount.h"
2017088Sbloom #include "kernel.h"
2117088Sbloom #include "acct.h"
2217088Sbloom #include "uio.h"
2337728Smckusick #include "syslog.h"
2412788Ssam 
2512788Ssam /*
2637728Smckusick  * Values associated with enabling and disabling accounting
2737728Smckusick  */
2837728Smckusick int	acctsuspend = 2;	/* stop accounting when < 2% free space left */
2937728Smckusick int	acctresume = 4;		/* resume when free space risen to > 4% */
3037728Smckusick struct	timeval chk = { 15, 0 };/* frequency to check space for accounting */
3137728Smckusick 
3237728Smckusick /*
3312788Ssam  * SHOULD REPLACE THIS WITH A DRIVER THAT CAN BE READ TO SIMPLIFY.
3412788Ssam  */
3537728Smckusick struct	vnode *acctp;
3637728Smckusick struct	vnode *savacctp;
3712788Ssam 
3812788Ssam /*
3912788Ssam  * Perform process accounting functions.
4012788Ssam  */
41*43379Smckusick /* ARGSUSED */
42*43379Smckusick sysacct(p, uap, retval)
43*43379Smckusick 	struct proc *p;
44*43379Smckusick 	struct args {
45*43379Smckusick 		char	*fname;
46*43379Smckusick 	} *uap;
47*43379Smckusick 	int *retval;
4812788Ssam {
4937728Smckusick 	register struct vnode *vp;
5016695Smckusick 	register struct nameidata *ndp = &u.u_nd;
5137728Smckusick 	extern int acctwatch();
5237728Smckusick 	struct vnode *oacctp;
53*43379Smckusick 	int error;
5412788Ssam 
55*43379Smckusick 	if (error = suser(u.u_cred, &u.u_acflag))
56*43379Smckusick 		RETURN (error);
5737553Smckusick 	if (savacctp) {
5837553Smckusick 		acctp = savacctp;
5937553Smckusick 		savacctp = NULL;
6037553Smckusick 	}
6137553Smckusick 	if (uap->fname==NULL) {
6237728Smckusick 		if (vp = acctp) {
6337553Smckusick 			acctp = NULL;
6437728Smckusick 			vrele(vp);
6537728Smckusick 			untimeout(acctwatch, (caddr_t)&chk);
6612788Ssam 		}
67*43379Smckusick 		RETURN (0);
6812788Ssam 	}
6937553Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
7037553Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
7137553Smckusick 	ndp->ni_dirp = uap->fname;
72*43379Smckusick 	if (error = namei(ndp))
73*43379Smckusick 		RETURN (error);
7437728Smckusick 	vp = ndp->ni_vp;
7537728Smckusick 	if (vp->v_type != VREG) {
7637728Smckusick 		vrele(vp);
77*43379Smckusick 		RETURN (EACCES);
7837553Smckusick 	}
7941400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
8037728Smckusick 		vrele(vp);
81*43379Smckusick 		RETURN (EROFS);
8237553Smckusick 	}
8337728Smckusick 	oacctp = acctp;
8437728Smckusick 	acctp = vp;
8537728Smckusick 	if (oacctp)
8637728Smckusick 		vrele(oacctp);
8737728Smckusick 	acctwatch(&chk);
88*43379Smckusick 	RETURN (0);
8912788Ssam }
9012788Ssam 
9112788Ssam /*
9237728Smckusick  * Periodically check the file system to see if accounting
9337728Smckusick  * should be turned on or off.
9412788Ssam  */
9537728Smckusick acctwatch(resettime)
9637728Smckusick 	struct timeval *resettime;
9712788Ssam {
9837728Smckusick 	struct statfs sb;
9912788Ssam 
10012788Ssam 	if (savacctp) {
10137728Smckusick 		(void)VFS_STATFS(savacctp->v_mount, &sb);
10237728Smckusick 		if (sb.f_bavail > acctresume * sb.f_blocks / 100) {
10312788Ssam 			acctp = savacctp;
10412788Ssam 			savacctp = NULL;
10537728Smckusick 			log(LOG_NOTICE, "Accounting resumed\n");
10637728Smckusick 			return;
10712788Ssam 		}
10812788Ssam 	}
10937728Smckusick 	if (acctp == NULL)
11012788Ssam 		return;
11137728Smckusick 	(void)VFS_STATFS(acctp->v_mount, &sb);
11237728Smckusick 	if (sb.f_bavail <= acctsuspend * sb.f_blocks / 100) {
11312788Ssam 		savacctp = acctp;
11412788Ssam 		acctp = NULL;
11537728Smckusick 		log(LOG_NOTICE, "Accounting suspended\n");
11637728Smckusick 	}
11737728Smckusick 	timeout(acctwatch, (caddr_t)resettime, hzto(resettime));
11837728Smckusick }
11937728Smckusick 
12037728Smckusick /*
12137728Smckusick  * On exit, write a record on the accounting file.
12237728Smckusick  */
123*43379Smckusick acct(p)
124*43379Smckusick 	register struct proc *p;
12537728Smckusick {
12637728Smckusick 	register struct rusage *ru;
12737728Smckusick 	struct vnode *vp;
12840803Smarc 	struct timeval t, ut, st;
12940803Smarc 	int i, s;
13037728Smckusick 	struct acct acctbuf;
13137728Smckusick 	register struct acct *ap = &acctbuf;
13237728Smckusick 
13337728Smckusick 	if ((vp = acctp) == NULL)
134*43379Smckusick 		return (0);
13540803Smarc 	bcopy(p->p_comm, ap->ac_comm, sizeof(ap->ac_comm));
13616715Ssam 	ru = &u.u_ru;
13740803Smarc 	s = splclock();
13840803Smarc 	ut = p->p_utime;
13940803Smarc 	st = p->p_stime;
14016715Ssam 	t = time;
14140803Smarc 	splx(s);
14240803Smarc 	ap->ac_utime = compress(ut.tv_sec, ut.tv_usec);
14340803Smarc 	ap->ac_stime = compress(st.tv_sec, st.tv_usec);
14416715Ssam 	timevalsub(&t, &u.u_start);
14516715Ssam 	ap->ac_etime = compress(t.tv_sec, t.tv_usec);
14616715Ssam 	ap->ac_btime = u.u_start.tv_sec;
147*43379Smckusick 	ap->ac_uid = p->p_ruid;
148*43379Smckusick 	ap->ac_gid = p->p_rgid;
14940803Smarc 	t = st;
15040803Smarc 	timevaladd(&t, &ut);
15116719Skarels 	if (i = t.tv_sec * hz + t.tv_usec / tick)
15216715Ssam 		ap->ac_mem = (ru->ru_ixrss+ru->ru_idrss+ru->ru_isrss) / i;
15316715Ssam 	else
15416715Ssam 		ap->ac_mem = 0;
15516715Ssam 	ap->ac_mem >>= CLSIZELOG2;
15626277Skarels 	ap->ac_io = compress(ru->ru_inblock + ru->ru_oublock, (long)0);
15742204Smarc 	if (p->p_flag&SCTTY && p->p_session->s_ttyp)
15840803Smarc 		ap->ac_tty = p->p_session->s_ttyp->t_dev;
15912788Ssam 	else
16012788Ssam 		ap->ac_tty = NODEV;
16112788Ssam 	ap->ac_flag = u.u_acflag;
162*43379Smckusick 	return (vn_rdwr(UIO_WRITE, vp, (caddr_t)ap, sizeof (acctbuf),
163*43379Smckusick 		(off_t)0, UIO_SYSSPACE, IO_UNIT|IO_APPEND, u.u_cred, (int *)0));
16412788Ssam }
16512788Ssam 
16612788Ssam /*
16712788Ssam  * Produce a pseudo-floating point representation
16812788Ssam  * with 3 bits base-8 exponent, 13 bits fraction.
16912788Ssam  */
17016715Ssam compress(t, ut)
17112788Ssam 	register long t;
17216715Ssam 	long ut;
17312788Ssam {
17412788Ssam 	register exp = 0, round = 0;
17512788Ssam 
17617501Skarels 	t = t * AHZ;  /* compiler will convert only this format to a shift */
17716715Ssam 	if (ut)
17817501Skarels 		t += ut / (1000000 / AHZ);
17912788Ssam 	while (t >= 8192) {
18012788Ssam 		exp++;
18112788Ssam 		round = t&04;
18212788Ssam 		t >>= 3;
18312788Ssam 	}
18412788Ssam 	if (round) {
18512788Ssam 		t++;
18612788Ssam 		if (t >= 8192) {
18712788Ssam 			t >>= 3;
18812788Ssam 			exp++;
18912788Ssam 		}
19012788Ssam 	}
19112788Ssam 	return ((exp<<13) + t);
19212788Ssam }
193