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