Commit | Line | Data |
---|---|---|
8c0dbd1c | 1 | /*- |
b435ea85 KB |
2 | * Copyright (c) 1982, 1986, 1989, 1993 |
3 | * The Regents of the University of California. All rights reserved. | |
adb35f79 KB |
4 | * (c) UNIX System Laboratories, Inc. |
5 | * All or some portions of this file are derived from material licensed | |
6 | * to the University of California by American Telephone and Telegraph | |
7 | * Co. or Unix System Laboratories, Inc. and are reproduced herein with | |
8 | * the permission of UNIX System Laboratories, Inc. | |
8c0dbd1c KB |
9 | * |
10 | * %sccs.include.proprietary.c% | |
da7c5cc6 | 11 | * |
4d3806d9 | 12 | * @(#)kern_acct.c 8.8 (Berkeley) %G% |
da7c5cc6 | 13 | */ |
06138e31 | 14 | |
38a01dbe KB |
15 | #include <sys/param.h> |
16 | #include <sys/systm.h> | |
17 | #include <sys/namei.h> | |
18 | #include <sys/resourcevar.h> | |
19 | #include <sys/proc.h> | |
20 | #include <sys/ioctl.h> | |
21 | #include <sys/termios.h> | |
22 | #include <sys/tty.h> | |
23 | #include <sys/vnode.h> | |
24 | #include <sys/mount.h> | |
25 | #include <sys/kernel.h> | |
26 | #include <sys/file.h> | |
27 | #include <sys/acct.h> | |
28 | #include <sys/syslog.h> | |
7dcb2b7d | 29 | #include <sys/syscallargs.h> |
c4ec2128 KM |
30 | |
31 | /* | |
32 | * Values associated with enabling and disabling accounting | |
33 | */ | |
34 | int acctsuspend = 2; /* stop accounting when < 2% free space left */ | |
35 | int acctresume = 4; /* resume when free space risen to > 4% */ | |
1e613993 | 36 | int acctchkfreq = 15; /* frequency (in seconds) to check space */ |
06138e31 SL |
37 | |
38 | /* | |
39 | * SHOULD REPLACE THIS WITH A DRIVER THAT CAN BE READ TO SIMPLIFY. | |
40 | */ | |
c4ec2128 KM |
41 | struct vnode *acctp; |
42 | struct vnode *savacctp; | |
06138e31 SL |
43 | |
44 | /* | |
02cf434b KM |
45 | * Enable or disable process accounting. |
46 | * | |
47 | * If a non-null filename is given, that file is used to store accounting | |
48 | * records on process exit. If a null filename is given process accounting | |
49 | * is suspended. If accounting is enabled, the system checks the amount | |
50 | * of freespace on the filesystem at timeval intervals. If the amount of | |
51 | * freespace is below acctsuspend percent, accounting is suspended. If | |
52 | * accounting has been suspended, and freespace rises above acctresume, | |
53 | * accounting is resumed. | |
06138e31 | 54 | */ |
fc0be3ee | 55 | acct(p, uap, retval) |
8c7d0e2a | 56 | struct proc *p; |
7dcb2b7d CD |
57 | struct acct_args /* { |
58 | syscallarg(char *) path; | |
59 | } */ *uap; | |
60 | register_t *retval; | |
06138e31 | 61 | { |
c4ec2128 | 62 | register struct vnode *vp; |
f02cb652 | 63 | extern void acctwatch __P((void *)); |
c4ec2128 | 64 | struct vnode *oacctp; |
8c7d0e2a | 65 | int error; |
3789a403 | 66 | struct nameidata nd; |
06138e31 | 67 | |
3789a403 | 68 | if (error = suser(p->p_ucred, &p->p_acflag)) |
d9c2f47f | 69 | return (error); |
849cbd39 KM |
70 | if (savacctp) { |
71 | acctp = savacctp; | |
72 | savacctp = NULL; | |
73 | } | |
7dcb2b7d | 74 | if (SCARG(uap, path) == NULL) { |
c4ec2128 | 75 | if (vp = acctp) { |
849cbd39 | 76 | acctp = NULL; |
79583d0d | 77 | error = vn_close(vp, FWRITE, p->p_ucred, p); |
f02cb652 | 78 | untimeout(acctwatch, NULL); |
dbba2129 | 79 | } |
79583d0d | 80 | return (error); |
849cbd39 | 81 | } |
7dcb2b7d | 82 | NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); |
9e7d3651 | 83 | if (error = vn_open(&nd, FWRITE, 0644)) |
d9c2f47f | 84 | return (error); |
3789a403 | 85 | vp = nd.ni_vp; |
4d3806d9 | 86 | VOP_UNLOCK(vp, 0, p); |
c4ec2128 | 87 | if (vp->v_type != VREG) { |
79583d0d | 88 | (void) vn_close(vp, FWRITE, p->p_ucred, p); |
d9c2f47f | 89 | return (EACCES); |
849cbd39 | 90 | } |
c4ec2128 KM |
91 | oacctp = acctp; |
92 | acctp = vp; | |
93 | if (oacctp) | |
79583d0d | 94 | error = vn_close(oacctp, FWRITE, p->p_ucred, p); |
f02cb652 | 95 | acctwatch(NULL); |
79583d0d | 96 | return (error); |
06138e31 SL |
97 | } |
98 | ||
06138e31 | 99 | /* |
c4ec2128 | 100 | * Periodically check the file system to see if accounting |
5ad4fbbd KM |
101 | * should be turned on or off. Beware the case where the vnode |
102 | * has been vgone()'d out from underneath us, e.g. when the file | |
103 | * system containing the accounting file has been forcibly unmounted. | |
06138e31 | 104 | */ |
f02cb652 CT |
105 | /* ARGSUSED */ |
106 | void | |
107 | acctwatch(a) | |
108 | void *a; | |
06138e31 | 109 | { |
c4ec2128 | 110 | struct statfs sb; |
06138e31 SL |
111 | |
112 | if (savacctp) { | |
5ad4fbbd KM |
113 | if (savacctp->v_type == VBAD) { |
114 | (void) vn_close(savacctp, FWRITE, NOCRED, NULL); | |
115 | savacctp = NULL; | |
116 | return; | |
117 | } | |
6bcdc4f3 | 118 | (void)VFS_STATFS(savacctp->v_mount, &sb, (struct proc *)0); |
c4ec2128 | 119 | if (sb.f_bavail > acctresume * sb.f_blocks / 100) { |
06138e31 SL |
120 | acctp = savacctp; |
121 | savacctp = NULL; | |
c4ec2128 | 122 | log(LOG_NOTICE, "Accounting resumed\n"); |
1e613993 KM |
123 | } |
124 | } else { | |
125 | if (acctp == NULL) | |
c4ec2128 | 126 | return; |
5ad4fbbd KM |
127 | if (acctp->v_type == VBAD) { |
128 | (void) vn_close(acctp, FWRITE, NOCRED, NULL); | |
129 | acctp = NULL; | |
130 | return; | |
131 | } | |
1e613993 KM |
132 | (void)VFS_STATFS(acctp->v_mount, &sb, (struct proc *)0); |
133 | if (sb.f_bavail <= acctsuspend * sb.f_blocks / 100) { | |
134 | savacctp = acctp; | |
135 | acctp = NULL; | |
136 | log(LOG_NOTICE, "Accounting suspended\n"); | |
06138e31 SL |
137 | } |
138 | } | |
1e613993 | 139 | timeout(acctwatch, NULL, acctchkfreq * hz); |
c4ec2128 KM |
140 | } |
141 | ||
142 | /* | |
02cf434b KM |
143 | * This routine calculates an accounting record for a process and, |
144 | * if accounting is enabled, writes it to the accounting file. | |
c4ec2128 | 145 | */ |
fc0be3ee | 146 | acct_process(p) |
8c7d0e2a | 147 | register struct proc *p; |
c4ec2128 KM |
148 | { |
149 | register struct rusage *ru; | |
150 | struct vnode *vp; | |
1cab08e7 | 151 | struct timeval t, ut, st; |
6b8f7051 | 152 | int error, i, s; |
c4ec2128 KM |
153 | struct acct acctbuf; |
154 | register struct acct *ap = &acctbuf; | |
155 | ||
6b8f7051 JSP |
156 | s = splclock(); |
157 | if ((vp = acctp) == NULL) { | |
158 | splx(s); | |
8c7d0e2a | 159 | return (0); |
6b8f7051 | 160 | } |
5ad4fbbd KM |
161 | if (vp->v_type == VBAD) { |
162 | (void) vn_close(vp, FWRITE, NOCRED, NULL); | |
163 | acctp = NULL; | |
6b8f7051 | 164 | splx(s); |
5ad4fbbd KM |
165 | return (0); |
166 | } | |
1cab08e7 | 167 | bcopy(p->p_comm, ap->ac_comm, sizeof(ap->ac_comm)); |
3789a403 | 168 | ru = &p->p_stats->p_ru; |
f02cb652 | 169 | calcru(p, &ut, &st, NULL); |
032146e9 | 170 | t = time; |
1cab08e7 MT |
171 | ap->ac_utime = compress(ut.tv_sec, ut.tv_usec); |
172 | ap->ac_stime = compress(st.tv_sec, st.tv_usec); | |
3789a403 | 173 | timevalsub(&t, &p->p_stats->p_start); |
032146e9 | 174 | ap->ac_etime = compress(t.tv_sec, t.tv_usec); |
3789a403 MK |
175 | ap->ac_btime = p->p_stats->p_start.tv_sec; |
176 | ap->ac_uid = p->p_cred->p_ruid; | |
177 | ap->ac_gid = p->p_cred->p_rgid; | |
1cab08e7 MT |
178 | t = st; |
179 | timevaladd(&t, &ut); | |
350f5463 | 180 | if (i = t.tv_sec * hz + t.tv_usec / tick) |
3789a403 | 181 | ap->ac_mem = (ru->ru_ixrss + ru->ru_idrss + ru->ru_isrss) / i; |
032146e9 SL |
182 | else |
183 | ap->ac_mem = 0; | |
01b0e233 | 184 | ap->ac_io = compress(ru->ru_inblock + ru->ru_oublock, (long)0); |
cf5ef508 | 185 | if (p->p_flag & P_CONTROLT && p->p_session->s_ttyp) |
1cab08e7 | 186 | ap->ac_tty = p->p_session->s_ttyp->t_dev; |
06138e31 SL |
187 | else |
188 | ap->ac_tty = NODEV; | |
3789a403 | 189 | ap->ac_flag = p->p_acflag; |
4c5d3e43 | 190 | VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); |
6b8f7051 | 191 | error = vn_rdwr(UIO_WRITE, vp, (caddr_t)ap, sizeof (acctbuf), (off_t)0, |
6bcdc4f3 | 192 | UIO_SYSSPACE, IO_UNIT|IO_APPEND, p->p_ucred, (int *)0, |
6b8f7051 JSP |
193 | (struct proc *)0); |
194 | splx(s); | |
195 | return (error); | |
06138e31 SL |
196 | } |
197 | ||
198 | /* | |
199 | * Produce a pseudo-floating point representation | |
200 | * with 3 bits base-8 exponent, 13 bits fraction. | |
201 | */ | |
032146e9 | 202 | compress(t, ut) |
06138e31 | 203 | register long t; |
032146e9 | 204 | long ut; |
06138e31 SL |
205 | { |
206 | register exp = 0, round = 0; | |
207 | ||
5d10e647 | 208 | t = t * AHZ; /* compiler will convert only this format to a shift */ |
032146e9 | 209 | if (ut) |
5d10e647 | 210 | t += ut / (1000000 / AHZ); |
06138e31 SL |
211 | while (t >= 8192) { |
212 | exp++; | |
213 | round = t&04; | |
214 | t >>= 3; | |
215 | } | |
216 | if (round) { | |
217 | t++; | |
218 | if (t >= 8192) { | |
219 | t >>= 3; | |
220 | exp++; | |
221 | } | |
222 | } | |
223 | return ((exp<<13) + t); | |
224 | } |