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