xref: /csrg-svn/sys/kern/kern_acct.c (revision 35809)
123365Smckusick /*
229085Smckusick  * Copyright (c) 1982, 1986 Regents of the University of California.
323365Smckusick  * All rights reserved.  The Berkeley software License Agreement
423365Smckusick  * specifies the terms and conditions for redistribution.
523365Smckusick  *
6*35809Smarc  *	@(#)kern_acct.c	7.3 (Berkeley) 10/18/88
723365Smckusick  */
812788Ssam 
917088Sbloom #include "param.h"
1017088Sbloom #include "systm.h"
1117088Sbloom #include "dir.h"
1217088Sbloom #include "user.h"
1317088Sbloom #include "inode.h"
1417088Sbloom #include "fs.h"
1517088Sbloom #include "kernel.h"
1617088Sbloom #include "acct.h"
1717088Sbloom #include "uio.h"
1812788Ssam 
1912788Ssam /*
2012788Ssam  * SHOULD REPLACE THIS WITH A DRIVER THAT CAN BE READ TO SIMPLIFY.
2112788Ssam  */
2212788Ssam struct	inode *acctp;
2312788Ssam struct	inode *savacctp;
2412788Ssam 
2512788Ssam /*
2612788Ssam  * Perform process accounting functions.
2712788Ssam  */
2812788Ssam sysacct()
2912788Ssam {
3012788Ssam 	register struct inode *ip;
3112788Ssam 	register struct a {
3212788Ssam 		char	*fname;
3312788Ssam 	} *uap = (struct a *)u.u_ap;
3416695Smckusick 	register struct nameidata *ndp = &u.u_nd;
3512788Ssam 
3612788Ssam 	if (suser()) {
3712788Ssam 		if (savacctp) {
3812788Ssam 			acctp = savacctp;
3912788Ssam 			savacctp = NULL;
4012788Ssam 		}
4112788Ssam 		if (uap->fname==NULL) {
4212788Ssam 			if (ip = acctp) {
4330166Skarels 				acctp = NULL;
4412788Ssam 				irele(ip);
4512788Ssam 			}
4612788Ssam 			return;
4712788Ssam 		}
4816695Smckusick 		ndp->ni_nameiop = LOOKUP | FOLLOW;
4916695Smckusick 		ndp->ni_segflg = UIO_USERSPACE;
5016695Smckusick 		ndp->ni_dirp = uap->fname;
5116695Smckusick 		ip = namei(ndp);
5226277Skarels 		if (ip == NULL)
5312788Ssam 			return;
5426277Skarels 		if ((ip->i_mode&IFMT) != IFREG) {
5512788Ssam 			u.u_error = EACCES;
5612788Ssam 			iput(ip);
5712788Ssam 			return;
5812788Ssam 		}
5920983Smckusick 		if (ip->i_fs->fs_ronly) {
6020983Smckusick 			u.u_error = EROFS;
6120983Smckusick 			iput(ip);
6220983Smckusick 			return;
6320983Smckusick 		}
6412788Ssam 		if (acctp && (acctp->i_number != ip->i_number ||
6512788Ssam 		    acctp->i_dev != ip->i_dev))
6612788Ssam 			irele(acctp);
6712788Ssam 		acctp = ip;
6812788Ssam 		iunlock(ip);
6912788Ssam 	}
7012788Ssam }
7112788Ssam 
7212788Ssam int	acctsuspend = 2;	/* stop accounting when < 2% free space left */
7312788Ssam int	acctresume = 4;		/* resume when free space risen to > 4% */
7412788Ssam 
7512788Ssam struct	acct acctbuf;
7612788Ssam /*
7712788Ssam  * On exit, write a record on the accounting file.
7812788Ssam  */
7912788Ssam acct()
8012788Ssam {
8112788Ssam 	register int i;
8212788Ssam 	register struct inode *ip;
8312788Ssam 	register struct fs *fs;
8416715Ssam 	register struct rusage *ru;
8512788Ssam 	off_t siz;
8616715Ssam 	struct timeval t;
8712788Ssam 	register struct acct *ap = &acctbuf;
8812788Ssam 
8912788Ssam 	if (savacctp) {
9012788Ssam 		fs = savacctp->i_fs;
9112788Ssam 		if (freespace(fs, fs->fs_minfree + acctresume) > 0) {
9212788Ssam 			acctp = savacctp;
9312788Ssam 			savacctp = NULL;
9412788Ssam 			printf("Accounting resumed\n");
9512788Ssam 		}
9612788Ssam 	}
9712788Ssam 	if ((ip = acctp) == NULL)
9812788Ssam 		return;
9912788Ssam 	fs = acctp->i_fs;
10012788Ssam 	if (freespace(fs, fs->fs_minfree + acctsuspend) <= 0) {
10112788Ssam 		savacctp = acctp;
10212788Ssam 		acctp = NULL;
10312788Ssam 		printf("Accounting suspended\n");
10412788Ssam 		return;
10512788Ssam 	}
10612788Ssam 	ilock(ip);
107*35809Smarc 	bcopy(u.u_comm, ap->ac_comm, sizeof(ap->ac_comm));
10816715Ssam 	ru = &u.u_ru;
10916715Ssam 	ap->ac_utime = compress(ru->ru_utime.tv_sec, ru->ru_utime.tv_usec);
11016715Ssam 	ap->ac_stime = compress(ru->ru_stime.tv_sec, ru->ru_stime.tv_usec);
11116715Ssam 	t = time;
11216715Ssam 	timevalsub(&t, &u.u_start);
11316715Ssam 	ap->ac_etime = compress(t.tv_sec, t.tv_usec);
11416715Ssam 	ap->ac_btime = u.u_start.tv_sec;
11512788Ssam 	ap->ac_uid = u.u_ruid;
11612788Ssam 	ap->ac_gid = u.u_rgid;
11716715Ssam 	t = ru->ru_stime;
11816715Ssam 	timevaladd(&t, &ru->ru_utime);
11916719Skarels 	if (i = t.tv_sec * hz + t.tv_usec / tick)
12016715Ssam 		ap->ac_mem = (ru->ru_ixrss+ru->ru_idrss+ru->ru_isrss) / i;
12116715Ssam 	else
12216715Ssam 		ap->ac_mem = 0;
12316715Ssam 	ap->ac_mem >>= CLSIZELOG2;
12426277Skarels 	ap->ac_io = compress(ru->ru_inblock + ru->ru_oublock, (long)0);
12512788Ssam 	if (u.u_ttyp)
12612788Ssam 		ap->ac_tty = u.u_ttyd;
12712788Ssam 	else
12812788Ssam 		ap->ac_tty = NODEV;
12912788Ssam 	ap->ac_flag = u.u_acflag;
13012788Ssam 	siz = ip->i_size;
13112788Ssam 	u.u_error = 0;				/* XXX */
13212788Ssam 	u.u_error =
13312788Ssam 	    rdwri(UIO_WRITE, ip, (caddr_t)ap, sizeof (acctbuf), siz,
13412788Ssam 		1, (int *)0);
13512788Ssam 	if (u.u_error)
13612788Ssam 		itrunc(ip, (u_long)siz);
13712788Ssam 	iunlock(ip);
13812788Ssam }
13912788Ssam 
14012788Ssam /*
14112788Ssam  * Produce a pseudo-floating point representation
14212788Ssam  * with 3 bits base-8 exponent, 13 bits fraction.
14312788Ssam  */
14416715Ssam compress(t, ut)
14512788Ssam 	register long t;
14616715Ssam 	long ut;
14712788Ssam {
14812788Ssam 	register exp = 0, round = 0;
14912788Ssam 
15017501Skarels 	t = t * AHZ;  /* compiler will convert only this format to a shift */
15116715Ssam 	if (ut)
15217501Skarels 		t += ut / (1000000 / AHZ);
15312788Ssam 	while (t >= 8192) {
15412788Ssam 		exp++;
15512788Ssam 		round = t&04;
15612788Ssam 		t >>= 3;
15712788Ssam 	}
15812788Ssam 	if (round) {
15912788Ssam 		t++;
16012788Ssam 		if (t >= 8192) {
16112788Ssam 			t >>= 3;
16212788Ssam 			exp++;
16312788Ssam 		}
16412788Ssam 	}
16512788Ssam 	return ((exp<<13) + t);
16612788Ssam }
167