xref: /csrg-svn/sys/kern/kern_acct.c (revision 59377)
149587Sbostic /*-
249587Sbostic  * Copyright (c) 1982, 1986, 1989 The Regents of the University of California.
349587Sbostic  * All rights reserved.
423365Smckusick  *
549587Sbostic  * %sccs.include.proprietary.c%
649587Sbostic  *
7*59377Smckusick  *	@(#)kern_acct.c	7.28 (Berkeley) 04/27/93
823365Smckusick  */
912788Ssam 
1056517Sbostic #include <sys/param.h>
1156517Sbostic #include <sys/systm.h>
1256517Sbostic #include <sys/namei.h>
1356517Sbostic #include <sys/resourcevar.h>
1456517Sbostic #include <sys/proc.h>
1556517Sbostic #include <sys/ioctl.h>
1656517Sbostic #include <sys/termios.h>
1756517Sbostic #include <sys/tty.h>
1856517Sbostic #include <sys/vnode.h>
1956517Sbostic #include <sys/mount.h>
2056517Sbostic #include <sys/kernel.h>
2156517Sbostic #include <sys/file.h>
2256517Sbostic #include <sys/acct.h>
2356517Sbostic #include <sys/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% */
3058149Smckusick int	acctchkfreq = 15;	/* frequency (in seconds) to check space */
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 /*
3949671Smckusick  * Enable or disable process accounting.
4049671Smckusick  *
4149671Smckusick  * If a non-null filename is given, that file is used to store accounting
4249671Smckusick  * records on process exit. If a null filename is given process accounting
4349671Smckusick  * is suspended. If accounting is enabled, the system checks the amount
4449671Smckusick  * of freespace on the filesystem at timeval intervals. If the amount of
4549671Smckusick  * freespace is below acctsuspend percent, accounting is suspended. If
4649671Smckusick  * accounting has been suspended, and freespace rises above acctresume,
4749671Smckusick  * accounting is resumed.
4812788Ssam  */
4943379Smckusick /* ARGSUSED */
5054919Storek struct sysacct_args {
5154919Storek 	char	*fname;
5254919Storek };
5343379Smckusick sysacct(p, uap, retval)
5443379Smckusick 	struct proc *p;
5554919Storek 	struct sysacct_args *uap;
5643379Smckusick 	int *retval;
5712788Ssam {
5837728Smckusick 	register struct vnode *vp;
5954789Storek 	extern void acctwatch __P((void *));
6037728Smckusick 	struct vnode *oacctp;
6143379Smckusick 	int error;
6247545Skarels 	struct nameidata nd;
6312788Ssam 
6447545Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
6544404Skarels 		return (error);
6637553Smckusick 	if (savacctp) {
6737553Smckusick 		acctp = savacctp;
6837553Smckusick 		savacctp = NULL;
6937553Smckusick 	}
7045055Smckusick 	if (uap->fname == NULL) {
7137728Smckusick 		if (vp = acctp) {
7237553Smckusick 			acctp = NULL;
7350107Smckusick 			error = vn_close(vp, FWRITE, p->p_ucred, p);
7454789Storek 			untimeout(acctwatch, NULL);
7512788Ssam 		}
7650107Smckusick 		return (error);
7712788Ssam 	}
7852307Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p);
7952307Smckusick 	if (error = vn_open(&nd, FWRITE, 0644))
8044404Skarels 		return (error);
8147545Skarels 	vp = nd.ni_vp;
8249916Smckusick 	VOP_UNLOCK(vp);
8337728Smckusick 	if (vp->v_type != VREG) {
8450107Smckusick 		(void) vn_close(vp, FWRITE, p->p_ucred, p);
8544404Skarels 		return (EACCES);
8637553Smckusick 	}
8737728Smckusick 	oacctp = acctp;
8837728Smckusick 	acctp = vp;
8937728Smckusick 	if (oacctp)
9050107Smckusick 		error = vn_close(oacctp, FWRITE, p->p_ucred, p);
9154789Storek 	acctwatch(NULL);
9250107Smckusick 	return (error);
9312788Ssam }
9412788Ssam 
9512788Ssam /*
9637728Smckusick  * Periodically check the file system to see if accounting
9737728Smckusick  * should be turned on or off.
9812788Ssam  */
9954789Storek /* ARGSUSED */
10054789Storek void
10154789Storek acctwatch(a)
10254789Storek 	void *a;
10312788Ssam {
10437728Smckusick 	struct statfs sb;
10512788Ssam 
10612788Ssam 	if (savacctp) {
10748021Smckusick 		(void)VFS_STATFS(savacctp->v_mount, &sb, (struct proc *)0);
10837728Smckusick 		if (sb.f_bavail > acctresume * sb.f_blocks / 100) {
10912788Ssam 			acctp = savacctp;
11012788Ssam 			savacctp = NULL;
11137728Smckusick 			log(LOG_NOTICE, "Accounting resumed\n");
11258149Smckusick 		}
11358149Smckusick 	} else {
11458149Smckusick 		if (acctp == NULL)
11537728Smckusick 			return;
11658149Smckusick 		(void)VFS_STATFS(acctp->v_mount, &sb, (struct proc *)0);
11758149Smckusick 		if (sb.f_bavail <= acctsuspend * sb.f_blocks / 100) {
11858149Smckusick 			savacctp = acctp;
11958149Smckusick 			acctp = NULL;
12058149Smckusick 			log(LOG_NOTICE, "Accounting suspended\n");
12112788Ssam 		}
12212788Ssam 	}
12358149Smckusick 	timeout(acctwatch, NULL, acctchkfreq * hz);
12437728Smckusick }
12537728Smckusick 
12637728Smckusick /*
12749671Smckusick  * This routine calculates an accounting record for a process and,
12849671Smckusick  * if accounting is enabled, writes it to the accounting file.
12937728Smckusick  */
13043379Smckusick acct(p)
13143379Smckusick 	register struct proc *p;
13237728Smckusick {
13337728Smckusick 	register struct rusage *ru;
13437728Smckusick 	struct vnode *vp;
13540803Smarc 	struct timeval t, ut, st;
13640803Smarc 	int i, s;
13737728Smckusick 	struct acct acctbuf;
13837728Smckusick 	register struct acct *ap = &acctbuf;
13937728Smckusick 
14037728Smckusick 	if ((vp = acctp) == NULL)
14143379Smckusick 		return (0);
14240803Smarc 	bcopy(p->p_comm, ap->ac_comm, sizeof(ap->ac_comm));
14347545Skarels 	ru = &p->p_stats->p_ru;
14454789Storek 	calcru(p, &ut, &st, NULL);
14540803Smarc 	s = splclock();
14616715Ssam 	t = time;
14740803Smarc 	splx(s);
14840803Smarc 	ap->ac_utime = compress(ut.tv_sec, ut.tv_usec);
14940803Smarc 	ap->ac_stime = compress(st.tv_sec, st.tv_usec);
15047545Skarels 	timevalsub(&t, &p->p_stats->p_start);
15116715Ssam 	ap->ac_etime = compress(t.tv_sec, t.tv_usec);
15247545Skarels 	ap->ac_btime = p->p_stats->p_start.tv_sec;
15347545Skarels 	ap->ac_uid = p->p_cred->p_ruid;
15447545Skarels 	ap->ac_gid = p->p_cred->p_rgid;
15540803Smarc 	t = st;
15640803Smarc 	timevaladd(&t, &ut);
15716719Skarels 	if (i = t.tv_sec * hz + t.tv_usec / tick)
15847545Skarels 		ap->ac_mem = (ru->ru_ixrss + ru->ru_idrss + ru->ru_isrss) / i;
15916715Ssam 	else
16016715Ssam 		ap->ac_mem = 0;
16126277Skarels 	ap->ac_io = compress(ru->ru_inblock + ru->ru_oublock, (long)0);
16242204Smarc 	if (p->p_flag&SCTTY && p->p_session->s_ttyp)
16340803Smarc 		ap->ac_tty = p->p_session->s_ttyp->t_dev;
16412788Ssam 	else
16512788Ssam 		ap->ac_tty = NODEV;
16647545Skarels 	ap->ac_flag = p->p_acflag;
167*59377Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
16848021Smckusick 	return (vn_rdwr(UIO_WRITE, vp, (caddr_t)ap, sizeof (acctbuf), (off_t)0,
16948021Smckusick 		UIO_SYSSPACE, IO_UNIT|IO_APPEND, p->p_ucred, (int *)0,
17048021Smckusick 		(struct proc *)0));
17112788Ssam }
17212788Ssam 
17312788Ssam /*
17412788Ssam  * Produce a pseudo-floating point representation
17512788Ssam  * with 3 bits base-8 exponent, 13 bits fraction.
17612788Ssam  */
17716715Ssam compress(t, ut)
17812788Ssam 	register long t;
17916715Ssam 	long ut;
18012788Ssam {
18112788Ssam 	register exp = 0, round = 0;
18212788Ssam 
18317501Skarels 	t = t * AHZ;  /* compiler will convert only this format to a shift */
18416715Ssam 	if (ut)
18517501Skarels 		t += ut / (1000000 / AHZ);
18612788Ssam 	while (t >= 8192) {
18712788Ssam 		exp++;
18812788Ssam 		round = t&04;
18912788Ssam 		t >>= 3;
19012788Ssam 	}
19112788Ssam 	if (round) {
19212788Ssam 		t++;
19312788Ssam 		if (t >= 8192) {
19412788Ssam 			t >>= 3;
19512788Ssam 			exp++;
19612788Ssam 		}
19712788Ssam 	}
19812788Ssam 	return ((exp<<13) + t);
19912788Ssam }
200