make it work better than once a second
[unix-history] / usr / src / sys / kern / kern_acct.c
CommitLineData
8c0dbd1c 1/*-
b435ea85
KB
2 * Copyright (c) 1982, 1986, 1989, 1993
3 * The Regents of the University of California. All rights reserved.
adb35f79
KB
4 * (c) UNIX System Laboratories, Inc.
5 * All or some portions of this file are derived from material licensed
6 * to the University of California by American Telephone and Telegraph
7 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8 * the permission of UNIX System Laboratories, Inc.
8c0dbd1c
KB
9 *
10 * %sccs.include.proprietary.c%
da7c5cc6 11 *
adb35f79 12 * @(#)kern_acct.c 8.3 (Berkeley) %G%
da7c5cc6 13 */
06138e31 14
38a01dbe
KB
15#include <sys/param.h>
16#include <sys/systm.h>
17#include <sys/namei.h>
18#include <sys/resourcevar.h>
19#include <sys/proc.h>
20#include <sys/ioctl.h>
21#include <sys/termios.h>
22#include <sys/tty.h>
23#include <sys/vnode.h>
24#include <sys/mount.h>
25#include <sys/kernel.h>
26#include <sys/file.h>
27#include <sys/acct.h>
28#include <sys/syslog.h>
c4ec2128
KM
29
30/*
31 * Values associated with enabling and disabling accounting
32 */
33int acctsuspend = 2; /* stop accounting when < 2% free space left */
34int acctresume = 4; /* resume when free space risen to > 4% */
1e613993 35int acctchkfreq = 15; /* frequency (in seconds) to check space */
06138e31
SL
36
37/*
38 * SHOULD REPLACE THIS WITH A DRIVER THAT CAN BE READ TO SIMPLIFY.
39 */
c4ec2128
KM
40struct vnode *acctp;
41struct vnode *savacctp;
06138e31
SL
42
43/*
02cf434b
KM
44 * Enable or disable process accounting.
45 *
46 * If a non-null filename is given, that file is used to store accounting
47 * records on process exit. If a null filename is given process accounting
48 * is suspended. If accounting is enabled, the system checks the amount
49 * of freespace on the filesystem at timeval intervals. If the amount of
50 * freespace is below acctsuspend percent, accounting is suspended. If
51 * accounting has been suspended, and freespace rises above acctresume,
52 * accounting is resumed.
06138e31 53 */
fc0be3ee 54struct acct_args {
9e97623a
CT
55 char *fname;
56};
fc0be3ee 57acct(p, uap, retval)
8c7d0e2a 58 struct proc *p;
fc0be3ee 59 struct acct_args *uap;
8c7d0e2a 60 int *retval;
06138e31 61{
c4ec2128 62 register struct vnode *vp;
f02cb652 63 extern void acctwatch __P((void *));
c4ec2128 64 struct vnode *oacctp;
8c7d0e2a 65 int error;
3789a403 66 struct nameidata nd;
06138e31 67
3789a403 68 if (error = suser(p->p_ucred, &p->p_acflag))
d9c2f47f 69 return (error);
849cbd39
KM
70 if (savacctp) {
71 acctp = savacctp;
72 savacctp = NULL;
73 }
46e4c6f8 74 if (uap->fname == NULL) {
c4ec2128 75 if (vp = acctp) {
849cbd39 76 acctp = NULL;
79583d0d 77 error = vn_close(vp, FWRITE, p->p_ucred, p);
f02cb652 78 untimeout(acctwatch, NULL);
dbba2129 79 }
79583d0d 80 return (error);
849cbd39 81 }
9e7d3651
KM
82 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p);
83 if (error = vn_open(&nd, FWRITE, 0644))
d9c2f47f 84 return (error);
3789a403 85 vp = nd.ni_vp;
c130850a 86 VOP_UNLOCK(vp);
c4ec2128 87 if (vp->v_type != VREG) {
79583d0d 88 (void) vn_close(vp, FWRITE, p->p_ucred, p);
d9c2f47f 89 return (EACCES);
849cbd39 90 }
c4ec2128
KM
91 oacctp = acctp;
92 acctp = vp;
93 if (oacctp)
79583d0d 94 error = vn_close(oacctp, FWRITE, p->p_ucred, p);
f02cb652 95 acctwatch(NULL);
79583d0d 96 return (error);
06138e31
SL
97}
98
06138e31 99/*
c4ec2128
KM
100 * Periodically check the file system to see if accounting
101 * should be turned on or off.
06138e31 102 */
f02cb652
CT
103/* ARGSUSED */
104void
105acctwatch(a)
106 void *a;
06138e31 107{
c4ec2128 108 struct statfs sb;
06138e31
SL
109
110 if (savacctp) {
6bcdc4f3 111 (void)VFS_STATFS(savacctp->v_mount, &sb, (struct proc *)0);
c4ec2128 112 if (sb.f_bavail > acctresume * sb.f_blocks / 100) {
06138e31
SL
113 acctp = savacctp;
114 savacctp = NULL;
c4ec2128 115 log(LOG_NOTICE, "Accounting resumed\n");
1e613993
KM
116 }
117 } else {
118 if (acctp == NULL)
c4ec2128 119 return;
1e613993
KM
120 (void)VFS_STATFS(acctp->v_mount, &sb, (struct proc *)0);
121 if (sb.f_bavail <= acctsuspend * sb.f_blocks / 100) {
122 savacctp = acctp;
123 acctp = NULL;
124 log(LOG_NOTICE, "Accounting suspended\n");
06138e31
SL
125 }
126 }
1e613993 127 timeout(acctwatch, NULL, acctchkfreq * hz);
c4ec2128
KM
128}
129
130/*
02cf434b
KM
131 * This routine calculates an accounting record for a process and,
132 * if accounting is enabled, writes it to the accounting file.
c4ec2128 133 */
fc0be3ee 134acct_process(p)
8c7d0e2a 135 register struct proc *p;
c4ec2128
KM
136{
137 register struct rusage *ru;
138 struct vnode *vp;
1cab08e7
MT
139 struct timeval t, ut, st;
140 int i, s;
c4ec2128
KM
141 struct acct acctbuf;
142 register struct acct *ap = &acctbuf;
143
144 if ((vp = acctp) == NULL)
8c7d0e2a 145 return (0);
1cab08e7 146 bcopy(p->p_comm, ap->ac_comm, sizeof(ap->ac_comm));
3789a403 147 ru = &p->p_stats->p_ru;
f02cb652 148 calcru(p, &ut, &st, NULL);
1cab08e7 149 s = splclock();
032146e9 150 t = time;
1cab08e7
MT
151 splx(s);
152 ap->ac_utime = compress(ut.tv_sec, ut.tv_usec);
153 ap->ac_stime = compress(st.tv_sec, st.tv_usec);
3789a403 154 timevalsub(&t, &p->p_stats->p_start);
032146e9 155 ap->ac_etime = compress(t.tv_sec, t.tv_usec);
3789a403
MK
156 ap->ac_btime = p->p_stats->p_start.tv_sec;
157 ap->ac_uid = p->p_cred->p_ruid;
158 ap->ac_gid = p->p_cred->p_rgid;
1cab08e7
MT
159 t = st;
160 timevaladd(&t, &ut);
350f5463 161 if (i = t.tv_sec * hz + t.tv_usec / tick)
3789a403 162 ap->ac_mem = (ru->ru_ixrss + ru->ru_idrss + ru->ru_isrss) / i;
032146e9
SL
163 else
164 ap->ac_mem = 0;
01b0e233 165 ap->ac_io = compress(ru->ru_inblock + ru->ru_oublock, (long)0);
cf5ef508 166 if (p->p_flag & P_CONTROLT && p->p_session->s_ttyp)
1cab08e7 167 ap->ac_tty = p->p_session->s_ttyp->t_dev;
06138e31
SL
168 else
169 ap->ac_tty = NODEV;
3789a403 170 ap->ac_flag = p->p_acflag;
2881f082 171 LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
6bcdc4f3
KM
172 return (vn_rdwr(UIO_WRITE, vp, (caddr_t)ap, sizeof (acctbuf), (off_t)0,
173 UIO_SYSSPACE, IO_UNIT|IO_APPEND, p->p_ucred, (int *)0,
174 (struct proc *)0));
06138e31
SL
175}
176
177/*
178 * Produce a pseudo-floating point representation
179 * with 3 bits base-8 exponent, 13 bits fraction.
180 */
032146e9 181compress(t, ut)
06138e31 182 register long t;
032146e9 183 long ut;
06138e31
SL
184{
185 register exp = 0, round = 0;
186
5d10e647 187 t = t * AHZ; /* compiler will convert only this format to a shift */
032146e9 188 if (ut)
5d10e647 189 t += ut / (1000000 / AHZ);
06138e31
SL
190 while (t >= 8192) {
191 exp++;
192 round = t&04;
193 t >>= 3;
194 }
195 if (round) {
196 t++;
197 if (t >= 8192) {
198 t >>= 3;
199 exp++;
200 }
201 }
202 return ((exp<<13) + t);
203}