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