added my responsibility for the `cpm' port
[unix-history] / sys / kern / kern_acct.c
CommitLineData
169d8a33
RG
1/*
2 * Copyright (c) UNIX System Laboratories, Inc. All or some portions
3 * of this file are derived from material licensed to the
4 * University of California by American Telephone and Telegraph Co.
5 * or UNIX System Laboratories, Inc. and are reproduced herein with
6 * the permission of UNIX System Laboratories, Inc.
7 */
15637ed4
RG
8/*
9 * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
10 * All rights reserved.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. All advertising materials mentioning features or use of this software
21 * must display the following acknowledgement:
22 * This product includes software developed by the University of
23 * California, Berkeley and its contributors.
24 * 4. Neither the name of the University nor the names of its contributors
25 * may be used to endorse or promote products derived from this software
26 * without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 * SUCH DAMAGE.
39 *
40 * from: @(#)kern_acct.c 7.18 (Berkeley) 5/11/91
169d8a33 41 * $Id: kern_acct.c,v 1.9 1993/11/25 01:32:48 wollman Exp $
15637ed4
RG
42 */
43
44#include "param.h"
45#include "systm.h"
46#include "namei.h"
47#include "resourcevar.h"
48#include "proc.h"
49#include "ioctl.h"
50#include "termios.h"
51#include "tty.h"
52#include "vnode.h"
53#include "mount.h"
54#include "kernel.h"
55#include "file.h"
56#include "acct.h"
57#include "syslog.h"
58
d0409160
NW
59#include "vm/vm.h"
60#include "vm/vm_param.h"
61
15637ed4
RG
62/*
63 * Values associated with enabling and disabling accounting
64 */
65int acctsuspend = 2; /* stop accounting when < 2% free space left */
66int acctresume = 4; /* resume when free space risen to > 4% */
f4e776c5 67struct timeval chk; /* frequency to check space for accounting */
d0409160
NW
68struct vnode *acctp = NULL; /* file to which to do accounting */
69struct vnode *savacctp = NULL; /* file to which to do accounting when space */
15637ed4 70
4c45483e
GW
71static void acctwatch(caddr_t, int);
72
15637ed4
RG
73/*
74 * Enable or disable process accounting.
75 *
76 * If a non-null filename is given, that file is used to store accounting
77 * records on process exit. If a null filename is given process accounting
78 * is suspended. If accounting is enabled, the system checks the amount
79 * of freespace on the filesystem at timeval intervals. If the amount of
80 * freespace is below acctsuspend percent, accounting is suspended. If
81 * accounting has been suspended, and freespace rises above acctresume,
82 * accounting is resumed.
83 */
3c7eb27c 84
d0409160 85/* Mark Tinguely (tinguely@plains.NoDak.edu) 8/10/93 */
3c7eb27c 86
e8f51f85
DG
87struct sysacct_args {
88 char *fname;
89};
90
15637ed4 91/* ARGSUSED */
4c45483e 92int
15637ed4
RG
93sysacct(p, uap, retval)
94 struct proc *p;
e8f51f85 95 struct sysacct_args *uap;
15637ed4
RG
96 int *retval;
97{
98
d0409160
NW
99 register struct nameidata *ndp;
100 struct nameidata nd;
101 struct vattr attr;
4c45483e 102 int rv;
d0409160
NW
103
104 if (p->p_ucred->cr_uid != 0)
105 return(EPERM); /* must be root */
106
15637ed4 107 /*
d0409160 108 * Step 1. turn off accounting (if on). exit if fname is nil
15637ed4 109 */
d0409160
NW
110
111 rv = 0; /* just in case nothing is open */
112 if (acctp != NULL) {
113 rv = vn_close(acctp, FWRITE, p->p_ucred, p);
114 untimeout(acctwatch, (caddr_t) &chk); /* turn off disk check */
115 acctp = NULL;
116 }
117 else if (savacctp != NULL ) {
118 rv = vn_close(savacctp, FWRITE, p->p_ucred, p);
119 untimeout(acctwatch, (caddr_t) &chk); /* turn off disk check */
120 savacctp = NULL;
121 }
122
123 if (uap->fname == NULL) /* accounting stopping complete */
124 return(rv);
125
126 /*
127 * Step 2. open accounting filename for writing.
128 */
129
130 nd.ni_segflg = UIO_USERSPACE;
131 nd.ni_dirp = uap->fname;
132
133 /* is it there? */
134 if (rv = vn_open(&nd, p, FWRITE, 0))
135 return (rv);
136
137 /* Step 2. Check the attributes on accounting file */
138 rv = VOP_GETATTR(nd.ni_vp, &attr, p->p_ucred, p);
139 if (rv)
140 goto acct_fail;
141
142 /* is filesystem writable, do I have permission to write and is
143 * a regular file?
144 */
145 if (nd.ni_vp->v_mount->mnt_flag & MNT_RDONLY) {
146 rv = EROFS; /* to be consistant with man page */
147 goto acct_fail;
148 }
149
150 if ((VOP_ACCESS(nd.ni_vp, VWRITE, p->p_ucred, p)) ||
151 (attr.va_type != VREG)) {
152 rv = EACCES; /* permission denied error */
153 goto acct_fail;
154 }
155
156 /* Step 3. Save the accounting file vnode, schedule freespace watch. */
157
158 acctp = nd.ni_vp;
159 savacctp = NULL;
d0409160 160 VOP_UNLOCK(acctp);
4c45483e 161 acctwatch((caddr_t)&chk, 0); /* look for full system */
d0409160
NW
162 return(0); /* end successfully */
163
164acct_fail:
165
166 vn_close(nd.ni_vp, FWRITE, p->p_ucred, p);
167 return(rv);
15637ed4
RG
168}
169
170/*
171 * Periodically check the file system to see if accounting
172 * should be turned on or off.
173 */
4c45483e
GW
174static void
175acctwatch(arg1, arg2)
176 caddr_t arg1;
177 int arg2;
15637ed4 178{
4c45483e 179 struct timeval *resettime = (struct timeval *)arg1;
15637ed4 180 struct statfs sb;
f4e776c5 181 int s;
15637ed4
RG
182
183 if (savacctp) {
184 (void)VFS_STATFS(savacctp->v_mount, &sb, (struct proc *)0);
185 if (sb.f_bavail > acctresume * sb.f_blocks / 100) {
186 acctp = savacctp;
187 savacctp = NULL;
188 log(LOG_NOTICE, "Accounting resumed\n");
189 return;
190 }
191 }
192 if (acctp == NULL)
193 return;
194 (void)VFS_STATFS(acctp->v_mount, &sb, (struct proc *)0);
195 if (sb.f_bavail <= acctsuspend * sb.f_blocks / 100) {
196 savacctp = acctp;
197 acctp = NULL;
198 log(LOG_NOTICE, "Accounting suspended\n");
199 }
0f34a638 200 s = splhigh(); *resettime = time; splx(s);
f4e776c5 201 resettime->tv_sec += 15;
15637ed4
RG
202 timeout(acctwatch, (caddr_t)resettime, hzto(resettime));
203}
204
205/*
206 * This routine calculates an accounting record for a process and,
207 * if accounting is enabled, writes it to the accounting file.
208 */
d0409160
NW
209
210/* Mark Tinguely (tinguely@plains.NoDak.edu) 8/10/93 */
211
4c45483e 212void
15637ed4
RG
213acct(p)
214 register struct proc *p;
215{
216
d0409160
NW
217 struct acct acct;
218 struct rusage *r;
219 int rv;
220 long i;
221 u_int cnt;
222 char *c;
223 comp_t int2comp();
224
225
226 if (acctp == NULL) /* accounting not turned on */
227 return;
228
229 /* Step 1. Get command name (remove path if necessary) */
230
231 strncpy(acct.ac_comm, p->p_comm, sizeof(acct.ac_comm));
232
233 /* Step 2. Get rest of information */
234
235 acct.ac_utime = int2comp((unsigned) p->p_utime.tv_sec * 1000000 + p->p_utime.tv_usec);
236 acct.ac_stime = int2comp((unsigned) p->p_stime.tv_sec * 1000000 + p->p_stime.tv_usec);
237 acct.ac_btime = p->p_stats->p_start.tv_sec;
238 /* elapse time = current - start */
239 i = (time.tv_sec - p->p_stats->p_start.tv_sec) * 1000000 +
240 (time.tv_usec - p->p_stats->p_start.tv_usec);
241 acct.ac_etime = int2comp((unsigned) i);
242
243 acct.ac_uid = p->p_cred->p_ruid;
244 acct.ac_gid = p->p_cred->p_rgid;
245
246 r = &p->p_stats->p_ru;
247 if (i = (p->p_utime.tv_sec + p->p_stime.tv_sec) * hz +
248 (p->p_utime.tv_usec + p->p_stime.tv_usec) / tick)
249 acct.ac_mem = (r->ru_ixrss + r->ru_idrss + r->ru_isrss) / i;
250 else
251 acct.ac_mem = 0;
252 acct.ac_io = int2comp((unsigned) (r->ru_inblock + r->ru_oublock) * 1000000);
253
254 if ((p->p_flag & SCTTY) && p->p_pgrp->pg_session->s_ttyp)
255 acct.ac_tty = p->p_pgrp->pg_session->s_ttyp->t_dev;
256 else
257 acct.ac_tty = NODEV;
258 acct.ac_flag = p->p_acflag;
259
260 /* Step 3. Write record to file */
261
262
263 rv = vn_rdwr(UIO_WRITE, acctp, (caddr_t) &acct, sizeof (acct),
264 (off_t)0, UIO_SYSSPACE, IO_APPEND|IO_UNIT, p->p_ucred, (int *) NULL,
265 p);
266}
267
268/* int2comp converts from ticks in a microsecond to ticks in 1/AHZ second
269 *
270 * comp_t is a psuedo-floating point number with 13 bits of
271 * mantissa and 3 bits of base 8 exponent and has resolution
272 * of 1/AHZ seconds.
273 *
274 * notice I already converted the incoming values into microseconds
275 * I need to convert back into AHZ ticks.
276 */
277
278/* Mark Tinguely (tinguely@plains.NoDak.edu) 8/10/93 */
279
280
281#define RES 13
282#define EXP 3
283#define MAXFRACT 1<<RES
284
285comp_t
286int2comp(mantissa)
287unsigned int mantissa;
288{
289 comp_t exp=0;
290
291 mantissa = mantissa * AHZ / 1000000; /* convert back to AHZ ticks */
292 while (mantissa > MAXFRACT) {
293 mantissa >>= EXP; /* base 8 exponent */
294 exp++;
295 }
296 exp <<= RES; /* move the exponent */
297 exp += mantissa; /* add on the manissa */
298 return (exp);
15637ed4 299}