Commit | Line | Data |
---|---|---|
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 | */ | |
65 | int acctsuspend = 2; /* stop accounting when < 2% free space left */ | |
66 | int acctresume = 4; /* resume when free space risen to > 4% */ | |
f4e776c5 | 67 | struct timeval chk; /* frequency to check space for accounting */ |
d0409160 NW |
68 | struct vnode *acctp = NULL; /* file to which to do accounting */ |
69 | struct vnode *savacctp = NULL; /* file to which to do accounting when space */ | |
15637ed4 | 70 | |
4c45483e GW |
71 | static 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 |
87 | struct sysacct_args { |
88 | char *fname; | |
89 | }; | |
90 | ||
15637ed4 | 91 | /* ARGSUSED */ |
4c45483e | 92 | int |
15637ed4 RG |
93 | sysacct(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 | ||
164 | acct_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 |
174 | static void |
175 | acctwatch(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 | 212 | void |
15637ed4 RG |
213 | acct(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 | ||
285 | comp_t | |
286 | int2comp(mantissa) | |
287 | unsigned 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 | } |