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 | |
d0409160 | 34 | * $Id: kern_acct.c,v 1.3 1993/10/16 15:24:07 rgrimes 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% */ | |
60 | struct timeval chk = { 15, 0 };/* 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 | |
15637ed4 RG |
78 | /* ARGSUSED */ |
79 | sysacct(p, uap, retval) | |
80 | struct proc *p; | |
d0409160 NW |
81 | struct args { |
82 | char *fname; | |
83 | } *uap; | |
15637ed4 RG |
84 | int *retval; |
85 | { | |
86 | ||
d0409160 NW |
87 | register struct nameidata *ndp; |
88 | struct nameidata nd; | |
89 | struct vattr attr; | |
90 | int rv, acctwatch(); | |
91 | ||
92 | if (p->p_ucred->cr_uid != 0) | |
93 | return(EPERM); /* must be root */ | |
94 | ||
15637ed4 | 95 | /* |
d0409160 | 96 | * Step 1. turn off accounting (if on). exit if fname is nil |
15637ed4 | 97 | */ |
d0409160 NW |
98 | |
99 | rv = 0; /* just in case nothing is open */ | |
100 | if (acctp != NULL) { | |
101 | rv = vn_close(acctp, FWRITE, p->p_ucred, p); | |
102 | untimeout(acctwatch, (caddr_t) &chk); /* turn off disk check */ | |
103 | acctp = NULL; | |
104 | } | |
105 | else if (savacctp != NULL ) { | |
106 | rv = vn_close(savacctp, FWRITE, p->p_ucred, p); | |
107 | untimeout(acctwatch, (caddr_t) &chk); /* turn off disk check */ | |
108 | savacctp = NULL; | |
109 | } | |
110 | ||
111 | if (uap->fname == NULL) /* accounting stopping complete */ | |
112 | return(rv); | |
113 | ||
114 | /* | |
115 | * Step 2. open accounting filename for writing. | |
116 | */ | |
117 | ||
118 | nd.ni_segflg = UIO_USERSPACE; | |
119 | nd.ni_dirp = uap->fname; | |
120 | ||
121 | /* is it there? */ | |
122 | if (rv = vn_open(&nd, p, FWRITE, 0)) | |
123 | return (rv); | |
124 | ||
125 | /* Step 2. Check the attributes on accounting file */ | |
126 | rv = VOP_GETATTR(nd.ni_vp, &attr, p->p_ucred, p); | |
127 | if (rv) | |
128 | goto acct_fail; | |
129 | ||
130 | /* is filesystem writable, do I have permission to write and is | |
131 | * a regular file? | |
132 | */ | |
133 | if (nd.ni_vp->v_mount->mnt_flag & MNT_RDONLY) { | |
134 | rv = EROFS; /* to be consistant with man page */ | |
135 | goto acct_fail; | |
136 | } | |
137 | ||
138 | if ((VOP_ACCESS(nd.ni_vp, VWRITE, p->p_ucred, p)) || | |
139 | (attr.va_type != VREG)) { | |
140 | rv = EACCES; /* permission denied error */ | |
141 | goto acct_fail; | |
142 | } | |
143 | ||
144 | /* Step 3. Save the accounting file vnode, schedule freespace watch. */ | |
145 | ||
146 | acctp = nd.ni_vp; | |
147 | savacctp = NULL; | |
148 | acctwatch(&chk); /* look for full system */ | |
149 | VOP_UNLOCK(acctp); | |
150 | return(0); /* end successfully */ | |
151 | ||
152 | acct_fail: | |
153 | ||
154 | vn_close(nd.ni_vp, FWRITE, p->p_ucred, p); | |
155 | return(rv); | |
15637ed4 RG |
156 | } |
157 | ||
158 | /* | |
159 | * Periodically check the file system to see if accounting | |
160 | * should be turned on or off. | |
161 | */ | |
162 | acctwatch(resettime) | |
163 | struct timeval *resettime; | |
164 | { | |
165 | struct statfs sb; | |
166 | ||
167 | if (savacctp) { | |
168 | (void)VFS_STATFS(savacctp->v_mount, &sb, (struct proc *)0); | |
169 | if (sb.f_bavail > acctresume * sb.f_blocks / 100) { | |
170 | acctp = savacctp; | |
171 | savacctp = NULL; | |
172 | log(LOG_NOTICE, "Accounting resumed\n"); | |
173 | return; | |
174 | } | |
175 | } | |
176 | if (acctp == NULL) | |
177 | return; | |
178 | (void)VFS_STATFS(acctp->v_mount, &sb, (struct proc *)0); | |
179 | if (sb.f_bavail <= acctsuspend * sb.f_blocks / 100) { | |
180 | savacctp = acctp; | |
181 | acctp = NULL; | |
182 | log(LOG_NOTICE, "Accounting suspended\n"); | |
183 | } | |
184 | timeout(acctwatch, (caddr_t)resettime, hzto(resettime)); | |
185 | } | |
186 | ||
187 | /* | |
188 | * This routine calculates an accounting record for a process and, | |
189 | * if accounting is enabled, writes it to the accounting file. | |
190 | */ | |
d0409160 NW |
191 | |
192 | /* Mark Tinguely (tinguely@plains.NoDak.edu) 8/10/93 */ | |
193 | ||
15637ed4 RG |
194 | acct(p) |
195 | register struct proc *p; | |
196 | { | |
197 | ||
d0409160 NW |
198 | struct acct acct; |
199 | struct rusage *r; | |
200 | int rv; | |
201 | long i; | |
202 | u_int cnt; | |
203 | char *c; | |
204 | comp_t int2comp(); | |
205 | ||
206 | ||
207 | if (acctp == NULL) /* accounting not turned on */ | |
208 | return; | |
209 | ||
210 | /* Step 1. Get command name (remove path if necessary) */ | |
211 | ||
212 | strncpy(acct.ac_comm, p->p_comm, sizeof(acct.ac_comm)); | |
213 | ||
214 | /* Step 2. Get rest of information */ | |
215 | ||
216 | acct.ac_utime = int2comp((unsigned) p->p_utime.tv_sec * 1000000 + p->p_utime.tv_usec); | |
217 | acct.ac_stime = int2comp((unsigned) p->p_stime.tv_sec * 1000000 + p->p_stime.tv_usec); | |
218 | acct.ac_btime = p->p_stats->p_start.tv_sec; | |
219 | /* elapse time = current - start */ | |
220 | i = (time.tv_sec - p->p_stats->p_start.tv_sec) * 1000000 + | |
221 | (time.tv_usec - p->p_stats->p_start.tv_usec); | |
222 | acct.ac_etime = int2comp((unsigned) i); | |
223 | ||
224 | acct.ac_uid = p->p_cred->p_ruid; | |
225 | acct.ac_gid = p->p_cred->p_rgid; | |
226 | ||
227 | r = &p->p_stats->p_ru; | |
228 | if (i = (p->p_utime.tv_sec + p->p_stime.tv_sec) * hz + | |
229 | (p->p_utime.tv_usec + p->p_stime.tv_usec) / tick) | |
230 | acct.ac_mem = (r->ru_ixrss + r->ru_idrss + r->ru_isrss) / i; | |
231 | else | |
232 | acct.ac_mem = 0; | |
233 | acct.ac_io = int2comp((unsigned) (r->ru_inblock + r->ru_oublock) * 1000000); | |
234 | ||
235 | if ((p->p_flag & SCTTY) && p->p_pgrp->pg_session->s_ttyp) | |
236 | acct.ac_tty = p->p_pgrp->pg_session->s_ttyp->t_dev; | |
237 | else | |
238 | acct.ac_tty = NODEV; | |
239 | acct.ac_flag = p->p_acflag; | |
240 | ||
241 | /* Step 3. Write record to file */ | |
242 | ||
243 | ||
244 | rv = vn_rdwr(UIO_WRITE, acctp, (caddr_t) &acct, sizeof (acct), | |
245 | (off_t)0, UIO_SYSSPACE, IO_APPEND|IO_UNIT, p->p_ucred, (int *) NULL, | |
246 | p); | |
247 | } | |
248 | ||
249 | /* int2comp converts from ticks in a microsecond to ticks in 1/AHZ second | |
250 | * | |
251 | * comp_t is a psuedo-floating point number with 13 bits of | |
252 | * mantissa and 3 bits of base 8 exponent and has resolution | |
253 | * of 1/AHZ seconds. | |
254 | * | |
255 | * notice I already converted the incoming values into microseconds | |
256 | * I need to convert back into AHZ ticks. | |
257 | */ | |
258 | ||
259 | /* Mark Tinguely (tinguely@plains.NoDak.edu) 8/10/93 */ | |
260 | ||
261 | ||
262 | #define RES 13 | |
263 | #define EXP 3 | |
264 | #define MAXFRACT 1<<RES | |
265 | ||
266 | comp_t | |
267 | int2comp(mantissa) | |
268 | unsigned int mantissa; | |
269 | { | |
270 | comp_t exp=0; | |
271 | ||
272 | mantissa = mantissa * AHZ / 1000000; /* convert back to AHZ ticks */ | |
273 | while (mantissa > MAXFRACT) { | |
274 | mantissa >>= EXP; /* base 8 exponent */ | |
275 | exp++; | |
276 | } | |
277 | exp <<= RES; /* move the exponent */ | |
278 | exp += mantissa; /* add on the manissa */ | |
279 | return (exp); | |
15637ed4 | 280 | } |