xref: /original-bsd/sys/kern/kern_acct.c (revision 972e85c3)
1 /*
2  * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  *
6  *	@(#)kern_acct.c	7.10 (Berkeley) 05/17/90
7  */
8 
9 #include "param.h"
10 #include "systm.h"
11 #include "time.h"
12 #include "proc.h"
13 #include "user.h"
14 #include "vnode.h"
15 #include "mount.h"
16 #include "kernel.h"
17 #include "acct.h"
18 #include "uio.h"
19 #include "syslog.h"
20 #include "ioctl.h"
21 #include "termios.h"
22 #include "tty.h"
23 
24 /*
25  * Values associated with enabling and disabling accounting
26  */
27 int	acctsuspend = 2;	/* stop accounting when < 2% free space left */
28 int	acctresume = 4;		/* resume when free space risen to > 4% */
29 struct	timeval chk = { 15, 0 };/* frequency to check space for accounting */
30 
31 /*
32  * SHOULD REPLACE THIS WITH A DRIVER THAT CAN BE READ TO SIMPLIFY.
33  */
34 struct	vnode *acctp;
35 struct	vnode *savacctp;
36 
37 /*
38  * Perform process accounting functions.
39  */
40 sysacct()
41 {
42 	register struct vnode *vp;
43 	register struct a {
44 		char	*fname;
45 	} *uap = (struct a *)u.u_ap;
46 	register struct nameidata *ndp = &u.u_nd;
47 	extern int acctwatch();
48 	struct vnode *oacctp;
49 
50 	if (u.u_error = suser(u.u_cred, &u.u_acflag))
51 		return;
52 	if (savacctp) {
53 		acctp = savacctp;
54 		savacctp = NULL;
55 	}
56 	if (uap->fname==NULL) {
57 		if (vp = acctp) {
58 			acctp = NULL;
59 			vrele(vp);
60 			untimeout(acctwatch, (caddr_t)&chk);
61 		}
62 		return;
63 	}
64 	ndp->ni_nameiop = LOOKUP | FOLLOW;
65 	ndp->ni_segflg = UIO_USERSPACE;
66 	ndp->ni_dirp = uap->fname;
67 	if (u.u_error = namei(ndp))
68 		return;
69 	vp = ndp->ni_vp;
70 	if (vp->v_type != VREG) {
71 		u.u_error = EACCES;
72 		vrele(vp);
73 		return;
74 	}
75 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
76 		u.u_error = EROFS;
77 		vrele(vp);
78 		return;
79 	}
80 	oacctp = acctp;
81 	acctp = vp;
82 	if (oacctp)
83 		vrele(oacctp);
84 	acctwatch(&chk);
85 }
86 
87 /*
88  * Periodically check the file system to see if accounting
89  * should be turned on or off.
90  */
91 acctwatch(resettime)
92 	struct timeval *resettime;
93 {
94 	struct statfs sb;
95 
96 	if (savacctp) {
97 		(void)VFS_STATFS(savacctp->v_mount, &sb);
98 		if (sb.f_bavail > acctresume * sb.f_blocks / 100) {
99 			acctp = savacctp;
100 			savacctp = NULL;
101 			log(LOG_NOTICE, "Accounting resumed\n");
102 			return;
103 		}
104 	}
105 	if (acctp == NULL)
106 		return;
107 	(void)VFS_STATFS(acctp->v_mount, &sb);
108 	if (sb.f_bavail <= acctsuspend * sb.f_blocks / 100) {
109 		savacctp = acctp;
110 		acctp = NULL;
111 		log(LOG_NOTICE, "Accounting suspended\n");
112 	}
113 	timeout(acctwatch, (caddr_t)resettime, hzto(resettime));
114 }
115 
116 /*
117  * On exit, write a record on the accounting file.
118  */
119 acct()
120 {
121 	register struct rusage *ru;
122 	struct vnode *vp;
123 	struct timeval t, ut, st;
124 	int i, s;
125 	struct acct acctbuf;
126 	register struct acct *ap = &acctbuf;
127 	register struct proc *p = u.u_procp;
128 
129 	if ((vp = acctp) == NULL)
130 		return;
131 	bcopy(p->p_comm, ap->ac_comm, sizeof(ap->ac_comm));
132 	ru = &u.u_ru;
133 	s = splclock();
134 	ut = p->p_utime;
135 	st = p->p_stime;
136 	t = time;
137 	splx(s);
138 	ap->ac_utime = compress(ut.tv_sec, ut.tv_usec);
139 	ap->ac_stime = compress(st.tv_sec, st.tv_usec);
140 	timevalsub(&t, &u.u_start);
141 	ap->ac_etime = compress(t.tv_sec, t.tv_usec);
142 	ap->ac_btime = u.u_start.tv_sec;
143 	ap->ac_uid = u.u_procp->p_ruid;
144 	ap->ac_gid = u.u_procp->p_rgid;
145 	t = st;
146 	timevaladd(&t, &ut);
147 	if (i = t.tv_sec * hz + t.tv_usec / tick)
148 		ap->ac_mem = (ru->ru_ixrss+ru->ru_idrss+ru->ru_isrss) / i;
149 	else
150 		ap->ac_mem = 0;
151 	ap->ac_mem >>= CLSIZELOG2;
152 	ap->ac_io = compress(ru->ru_inblock + ru->ru_oublock, (long)0);
153 	if (p->p_flag&SCTTY && p->p_session->s_ttyp)
154 		ap->ac_tty = p->p_session->s_ttyp->t_dev;
155 	else
156 		ap->ac_tty = NODEV;
157 	ap->ac_flag = u.u_acflag;
158 	u.u_error = vn_rdwr(UIO_WRITE, vp, (caddr_t)ap, sizeof (acctbuf),
159 		(off_t)0, UIO_SYSSPACE, IO_UNIT|IO_APPEND, u.u_cred, (int *)0);
160 }
161 
162 /*
163  * Produce a pseudo-floating point representation
164  * with 3 bits base-8 exponent, 13 bits fraction.
165  */
166 compress(t, ut)
167 	register long t;
168 	long ut;
169 {
170 	register exp = 0, round = 0;
171 
172 	t = t * AHZ;  /* compiler will convert only this format to a shift */
173 	if (ut)
174 		t += ut / (1000000 / AHZ);
175 	while (t >= 8192) {
176 		exp++;
177 		round = t&04;
178 		t >>= 3;
179 	}
180 	if (round) {
181 		t++;
182 		if (t >= 8192) {
183 			t >>= 3;
184 			exp++;
185 		}
186 	}
187 	return ((exp<<13) + t);
188 }
189