xref: /csrg-svn/sys/kern/kern_acct.c (revision 38931)
123365Smckusick /*
237728Smckusick  * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
337728Smckusick  * All rights reserved.
423365Smckusick  *
537728Smckusick  * Redistribution and use in source and binary forms are permitted
637728Smckusick  * provided that the above copyright notice and this paragraph are
737728Smckusick  * duplicated in all such forms and that any documentation,
837728Smckusick  * advertising materials, and other materials related to such
937728Smckusick  * distribution and use acknowledge that the software was developed
1037728Smckusick  * by the University of California, Berkeley.  The name of the
1137728Smckusick  * University may not be used to endorse or promote products derived
1237728Smckusick  * from this software without specific prior written permission.
1337728Smckusick  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1437728Smckusick  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1537728Smckusick  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1637728Smckusick  *
17*38931Skarels  *	@(#)kern_acct.c	7.6 (Berkeley) 09/03/89
1823365Smckusick  */
1912788Ssam 
2017088Sbloom #include "param.h"
2117088Sbloom #include "systm.h"
22*38931Skarels #include "time.h"
23*38931Skarels #include "proc.h"
2417088Sbloom #include "user.h"
2537728Smckusick #include "vnode.h"
2637728Smckusick #include "mount.h"
2717088Sbloom #include "kernel.h"
2817088Sbloom #include "acct.h"
2917088Sbloom #include "uio.h"
3037728Smckusick #include "syslog.h"
3112788Ssam 
3212788Ssam /*
3337728Smckusick  * Values associated with enabling and disabling accounting
3437728Smckusick  */
3537728Smckusick int	acctsuspend = 2;	/* stop accounting when < 2% free space left */
3637728Smckusick int	acctresume = 4;		/* resume when free space risen to > 4% */
3737728Smckusick struct	timeval chk = { 15, 0 };/* frequency to check space for accounting */
3837728Smckusick 
3937728Smckusick /*
4012788Ssam  * SHOULD REPLACE THIS WITH A DRIVER THAT CAN BE READ TO SIMPLIFY.
4112788Ssam  */
4237728Smckusick struct	vnode *acctp;
4337728Smckusick struct	vnode *savacctp;
4412788Ssam 
4512788Ssam /*
4612788Ssam  * Perform process accounting functions.
4712788Ssam  */
4812788Ssam sysacct()
4912788Ssam {
5037728Smckusick 	register struct vnode *vp;
5112788Ssam 	register struct a {
5212788Ssam 		char	*fname;
5312788Ssam 	} *uap = (struct a *)u.u_ap;
5416695Smckusick 	register struct nameidata *ndp = &u.u_nd;
5537728Smckusick 	extern int acctwatch();
5637728Smckusick 	struct vnode *oacctp;
5712788Ssam 
5837553Smckusick 	if (u.u_error = suser(u.u_cred, &u.u_acflag))
5937553Smckusick 		return;
6037553Smckusick 	if (savacctp) {
6137553Smckusick 		acctp = savacctp;
6237553Smckusick 		savacctp = NULL;
6337553Smckusick 	}
6437553Smckusick 	if (uap->fname==NULL) {
6537728Smckusick 		if (vp = acctp) {
6637553Smckusick 			acctp = NULL;
6737728Smckusick 			vrele(vp);
6837728Smckusick 			untimeout(acctwatch, (caddr_t)&chk);
6912788Ssam 		}
7037553Smckusick 		return;
7112788Ssam 	}
7237553Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
7337553Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
7437553Smckusick 	ndp->ni_dirp = uap->fname;
7537728Smckusick 	if (u.u_error = namei(ndp))
7637553Smckusick 		return;
7737728Smckusick 	vp = ndp->ni_vp;
7837728Smckusick 	if (vp->v_type != VREG) {
7937553Smckusick 		u.u_error = EACCES;
8037728Smckusick 		vrele(vp);
8137553Smckusick 		return;
8237553Smckusick 	}
8337728Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
8437553Smckusick 		u.u_error = EROFS;
8537728Smckusick 		vrele(vp);
8637553Smckusick 		return;
8737553Smckusick 	}
8837728Smckusick 	oacctp = acctp;
8937728Smckusick 	acctp = vp;
9037728Smckusick 	if (oacctp)
9137728Smckusick 		vrele(oacctp);
9237728Smckusick 	acctwatch(&chk);
9312788Ssam }
9412788Ssam 
9512788Ssam /*
9637728Smckusick  * Periodically check the file system to see if accounting
9737728Smckusick  * should be turned on or off.
9812788Ssam  */
9937728Smckusick acctwatch(resettime)
10037728Smckusick 	struct timeval *resettime;
10112788Ssam {
10237728Smckusick 	struct statfs sb;
10312788Ssam 
10412788Ssam 	if (savacctp) {
10537728Smckusick 		(void)VFS_STATFS(savacctp->v_mount, &sb);
10637728Smckusick 		if (sb.f_bavail > acctresume * sb.f_blocks / 100) {
10712788Ssam 			acctp = savacctp;
10812788Ssam 			savacctp = NULL;
10937728Smckusick 			log(LOG_NOTICE, "Accounting resumed\n");
11037728Smckusick 			return;
11112788Ssam 		}
11212788Ssam 	}
11337728Smckusick 	if (acctp == NULL)
11412788Ssam 		return;
11537728Smckusick 	(void)VFS_STATFS(acctp->v_mount, &sb);
11637728Smckusick 	if (sb.f_bavail <= acctsuspend * sb.f_blocks / 100) {
11712788Ssam 		savacctp = acctp;
11812788Ssam 		acctp = NULL;
11937728Smckusick 		log(LOG_NOTICE, "Accounting suspended\n");
12037728Smckusick 	}
12137728Smckusick 	timeout(acctwatch, (caddr_t)resettime, hzto(resettime));
12237728Smckusick }
12337728Smckusick 
12437728Smckusick /*
12537728Smckusick  * On exit, write a record on the accounting file.
12637728Smckusick  */
12737728Smckusick acct()
12837728Smckusick {
12937728Smckusick 	register struct rusage *ru;
13037728Smckusick 	struct vnode *vp;
13137728Smckusick 	struct timeval t;
13237728Smckusick 	int i;
13337728Smckusick 	struct acct acctbuf;
13437728Smckusick 	register struct acct *ap = &acctbuf;
13537728Smckusick 
13637728Smckusick 	if ((vp = acctp) == NULL)
13712788Ssam 		return;
13835809Smarc 	bcopy(u.u_comm, ap->ac_comm, sizeof(ap->ac_comm));
13916715Ssam 	ru = &u.u_ru;
14016715Ssam 	ap->ac_utime = compress(ru->ru_utime.tv_sec, ru->ru_utime.tv_usec);
14116715Ssam 	ap->ac_stime = compress(ru->ru_stime.tv_sec, ru->ru_stime.tv_usec);
14216715Ssam 	t = time;
14316715Ssam 	timevalsub(&t, &u.u_start);
14416715Ssam 	ap->ac_etime = compress(t.tv_sec, t.tv_usec);
14516715Ssam 	ap->ac_btime = u.u_start.tv_sec;
146*38931Skarels 	ap->ac_uid = u.u_procp->p_ruid;
147*38931Skarels 	ap->ac_gid = u.u_procp->p_rgid;
14816715Ssam 	t = ru->ru_stime;
14916715Ssam 	timevaladd(&t, &ru->ru_utime);
15016719Skarels 	if (i = t.tv_sec * hz + t.tv_usec / tick)
15116715Ssam 		ap->ac_mem = (ru->ru_ixrss+ru->ru_idrss+ru->ru_isrss) / i;
15216715Ssam 	else
15316715Ssam 		ap->ac_mem = 0;
15416715Ssam 	ap->ac_mem >>= CLSIZELOG2;
15526277Skarels 	ap->ac_io = compress(ru->ru_inblock + ru->ru_oublock, (long)0);
15612788Ssam 	if (u.u_ttyp)
15712788Ssam 		ap->ac_tty = u.u_ttyd;
15812788Ssam 	else
15912788Ssam 		ap->ac_tty = NODEV;
16012788Ssam 	ap->ac_flag = u.u_acflag;
16137728Smckusick 	u.u_error = vn_rdwr(UIO_WRITE, vp, (caddr_t)ap, sizeof (acctbuf),
16237728Smckusick 		(off_t)0, UIO_SYSSPACE, IO_UNIT|IO_APPEND, u.u_cred, (int *)0);
16312788Ssam }
16412788Ssam 
16512788Ssam /*
16612788Ssam  * Produce a pseudo-floating point representation
16712788Ssam  * with 3 bits base-8 exponent, 13 bits fraction.
16812788Ssam  */
16916715Ssam compress(t, ut)
17012788Ssam 	register long t;
17116715Ssam 	long ut;
17212788Ssam {
17312788Ssam 	register exp = 0, round = 0;
17412788Ssam 
17517501Skarels 	t = t * AHZ;  /* compiler will convert only this format to a shift */
17616715Ssam 	if (ut)
17717501Skarels 		t += ut / (1000000 / AHZ);
17812788Ssam 	while (t >= 8192) {
17912788Ssam 		exp++;
18012788Ssam 		round = t&04;
18112788Ssam 		t >>= 3;
18212788Ssam 	}
18312788Ssam 	if (round) {
18412788Ssam 		t++;
18512788Ssam 		if (t >= 8192) {
18612788Ssam 			t >>= 3;
18712788Ssam 			exp++;
18812788Ssam 		}
18912788Ssam 	}
19012788Ssam 	return ((exp<<13) + t);
19112788Ssam }
192