xref: /csrg-svn/sys/kern/kern_acct.c (revision 37728)
123365Smckusick /*
2*37728Smckusick  * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
3*37728Smckusick  * All rights reserved.
423365Smckusick  *
5*37728Smckusick  * Redistribution and use in source and binary forms are permitted
6*37728Smckusick  * provided that the above copyright notice and this paragraph are
7*37728Smckusick  * duplicated in all such forms and that any documentation,
8*37728Smckusick  * advertising materials, and other materials related to such
9*37728Smckusick  * distribution and use acknowledge that the software was developed
10*37728Smckusick  * by the University of California, Berkeley.  The name of the
11*37728Smckusick  * University may not be used to endorse or promote products derived
12*37728Smckusick  * from this software without specific prior written permission.
13*37728Smckusick  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14*37728Smckusick  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15*37728Smckusick  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16*37728Smckusick  *
17*37728Smckusick  *	@(#)kern_acct.c	7.5 (Berkeley) 05/09/89
1823365Smckusick  */
1912788Ssam 
2017088Sbloom #include "param.h"
2117088Sbloom #include "systm.h"
2217088Sbloom #include "user.h"
23*37728Smckusick #include "vnode.h"
24*37728Smckusick #include "mount.h"
2517088Sbloom #include "kernel.h"
2617088Sbloom #include "acct.h"
2717088Sbloom #include "uio.h"
28*37728Smckusick #include "syslog.h"
2912788Ssam 
3012788Ssam /*
31*37728Smckusick  * Values associated with enabling and disabling accounting
32*37728Smckusick  */
33*37728Smckusick int	acctsuspend = 2;	/* stop accounting when < 2% free space left */
34*37728Smckusick int	acctresume = 4;		/* resume when free space risen to > 4% */
35*37728Smckusick struct	timeval chk = { 15, 0 };/* frequency to check space for accounting */
36*37728Smckusick 
37*37728Smckusick /*
3812788Ssam  * SHOULD REPLACE THIS WITH A DRIVER THAT CAN BE READ TO SIMPLIFY.
3912788Ssam  */
40*37728Smckusick struct	vnode *acctp;
41*37728Smckusick struct	vnode *savacctp;
4212788Ssam 
4312788Ssam /*
4412788Ssam  * Perform process accounting functions.
4512788Ssam  */
4612788Ssam sysacct()
4712788Ssam {
48*37728Smckusick 	register struct vnode *vp;
4912788Ssam 	register struct a {
5012788Ssam 		char	*fname;
5112788Ssam 	} *uap = (struct a *)u.u_ap;
5216695Smckusick 	register struct nameidata *ndp = &u.u_nd;
53*37728Smckusick 	extern int acctwatch();
54*37728Smckusick 	struct vnode *oacctp;
5512788Ssam 
5637553Smckusick 	if (u.u_error = suser(u.u_cred, &u.u_acflag))
5737553Smckusick 		return;
5837553Smckusick 	if (savacctp) {
5937553Smckusick 		acctp = savacctp;
6037553Smckusick 		savacctp = NULL;
6137553Smckusick 	}
6237553Smckusick 	if (uap->fname==NULL) {
63*37728Smckusick 		if (vp = acctp) {
6437553Smckusick 			acctp = NULL;
65*37728Smckusick 			vrele(vp);
66*37728Smckusick 			untimeout(acctwatch, (caddr_t)&chk);
6712788Ssam 		}
6837553Smckusick 		return;
6912788Ssam 	}
7037553Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
7137553Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
7237553Smckusick 	ndp->ni_dirp = uap->fname;
73*37728Smckusick 	if (u.u_error = namei(ndp))
7437553Smckusick 		return;
75*37728Smckusick 	vp = ndp->ni_vp;
76*37728Smckusick 	if (vp->v_type != VREG) {
7737553Smckusick 		u.u_error = EACCES;
78*37728Smckusick 		vrele(vp);
7937553Smckusick 		return;
8037553Smckusick 	}
81*37728Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
8237553Smckusick 		u.u_error = EROFS;
83*37728Smckusick 		vrele(vp);
8437553Smckusick 		return;
8537553Smckusick 	}
86*37728Smckusick 	oacctp = acctp;
87*37728Smckusick 	acctp = vp;
88*37728Smckusick 	if (oacctp)
89*37728Smckusick 		vrele(oacctp);
90*37728Smckusick 	acctwatch(&chk);
9112788Ssam }
9212788Ssam 
9312788Ssam /*
94*37728Smckusick  * Periodically check the file system to see if accounting
95*37728Smckusick  * should be turned on or off.
9612788Ssam  */
97*37728Smckusick acctwatch(resettime)
98*37728Smckusick 	struct timeval *resettime;
9912788Ssam {
100*37728Smckusick 	struct statfs sb;
10112788Ssam 
10212788Ssam 	if (savacctp) {
103*37728Smckusick 		(void)VFS_STATFS(savacctp->v_mount, &sb);
104*37728Smckusick 		if (sb.f_bavail > acctresume * sb.f_blocks / 100) {
10512788Ssam 			acctp = savacctp;
10612788Ssam 			savacctp = NULL;
107*37728Smckusick 			log(LOG_NOTICE, "Accounting resumed\n");
108*37728Smckusick 			return;
10912788Ssam 		}
11012788Ssam 	}
111*37728Smckusick 	if (acctp == NULL)
11212788Ssam 		return;
113*37728Smckusick 	(void)VFS_STATFS(acctp->v_mount, &sb);
114*37728Smckusick 	if (sb.f_bavail <= acctsuspend * sb.f_blocks / 100) {
11512788Ssam 		savacctp = acctp;
11612788Ssam 		acctp = NULL;
117*37728Smckusick 		log(LOG_NOTICE, "Accounting suspended\n");
118*37728Smckusick 	}
119*37728Smckusick 	timeout(acctwatch, (caddr_t)resettime, hzto(resettime));
120*37728Smckusick }
121*37728Smckusick 
122*37728Smckusick /*
123*37728Smckusick  * On exit, write a record on the accounting file.
124*37728Smckusick  */
125*37728Smckusick acct()
126*37728Smckusick {
127*37728Smckusick 	register struct rusage *ru;
128*37728Smckusick 	struct vnode *vp;
129*37728Smckusick 	struct timeval t;
130*37728Smckusick 	int i;
131*37728Smckusick 	struct acct acctbuf;
132*37728Smckusick 	register struct acct *ap = &acctbuf;
133*37728Smckusick 
134*37728Smckusick 	if ((vp = acctp) == NULL)
13512788Ssam 		return;
13635809Smarc 	bcopy(u.u_comm, ap->ac_comm, sizeof(ap->ac_comm));
13716715Ssam 	ru = &u.u_ru;
13816715Ssam 	ap->ac_utime = compress(ru->ru_utime.tv_sec, ru->ru_utime.tv_usec);
13916715Ssam 	ap->ac_stime = compress(ru->ru_stime.tv_sec, ru->ru_stime.tv_usec);
14016715Ssam 	t = time;
14116715Ssam 	timevalsub(&t, &u.u_start);
14216715Ssam 	ap->ac_etime = compress(t.tv_sec, t.tv_usec);
14316715Ssam 	ap->ac_btime = u.u_start.tv_sec;
14412788Ssam 	ap->ac_uid = u.u_ruid;
14512788Ssam 	ap->ac_gid = u.u_rgid;
14616715Ssam 	t = ru->ru_stime;
14716715Ssam 	timevaladd(&t, &ru->ru_utime);
14816719Skarels 	if (i = t.tv_sec * hz + t.tv_usec / tick)
14916715Ssam 		ap->ac_mem = (ru->ru_ixrss+ru->ru_idrss+ru->ru_isrss) / i;
15016715Ssam 	else
15116715Ssam 		ap->ac_mem = 0;
15216715Ssam 	ap->ac_mem >>= CLSIZELOG2;
15326277Skarels 	ap->ac_io = compress(ru->ru_inblock + ru->ru_oublock, (long)0);
15412788Ssam 	if (u.u_ttyp)
15512788Ssam 		ap->ac_tty = u.u_ttyd;
15612788Ssam 	else
15712788Ssam 		ap->ac_tty = NODEV;
15812788Ssam 	ap->ac_flag = u.u_acflag;
159*37728Smckusick 	u.u_error = vn_rdwr(UIO_WRITE, vp, (caddr_t)ap, sizeof (acctbuf),
160*37728Smckusick 		(off_t)0, UIO_SYSSPACE, IO_UNIT|IO_APPEND, u.u_cred, (int *)0);
16112788Ssam }
16212788Ssam 
16312788Ssam /*
16412788Ssam  * Produce a pseudo-floating point representation
16512788Ssam  * with 3 bits base-8 exponent, 13 bits fraction.
16612788Ssam  */
16716715Ssam compress(t, ut)
16812788Ssam 	register long t;
16916715Ssam 	long ut;
17012788Ssam {
17112788Ssam 	register exp = 0, round = 0;
17212788Ssam 
17317501Skarels 	t = t * AHZ;  /* compiler will convert only this format to a shift */
17416715Ssam 	if (ut)
17517501Skarels 		t += ut / (1000000 / AHZ);
17612788Ssam 	while (t >= 8192) {
17712788Ssam 		exp++;
17812788Ssam 		round = t&04;
17912788Ssam 		t >>= 3;
18012788Ssam 	}
18112788Ssam 	if (round) {
18212788Ssam 		t++;
18312788Ssam 		if (t >= 8192) {
18412788Ssam 			t >>= 3;
18512788Ssam 			exp++;
18612788Ssam 		}
18712788Ssam 	}
18812788Ssam 	return ((exp<<13) + t);
18912788Ssam }
190