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 | * |
adb35f79 | 12 | * @(#)kern_acct.c 8.3 (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> | |
c4ec2128 KM |
29 | |
30 | /* | |
31 | * Values associated with enabling and disabling accounting | |
32 | */ | |
33 | int acctsuspend = 2; /* stop accounting when < 2% free space left */ | |
34 | int acctresume = 4; /* resume when free space risen to > 4% */ | |
1e613993 | 35 | int acctchkfreq = 15; /* frequency (in seconds) to check space */ |
06138e31 SL |
36 | |
37 | /* | |
38 | * SHOULD REPLACE THIS WITH A DRIVER THAT CAN BE READ TO SIMPLIFY. | |
39 | */ | |
c4ec2128 KM |
40 | struct vnode *acctp; |
41 | struct vnode *savacctp; | |
06138e31 SL |
42 | |
43 | /* | |
02cf434b KM |
44 | * Enable or disable process accounting. |
45 | * | |
46 | * If a non-null filename is given, that file is used to store accounting | |
47 | * records on process exit. If a null filename is given process accounting | |
48 | * is suspended. If accounting is enabled, the system checks the amount | |
49 | * of freespace on the filesystem at timeval intervals. If the amount of | |
50 | * freespace is below acctsuspend percent, accounting is suspended. If | |
51 | * accounting has been suspended, and freespace rises above acctresume, | |
52 | * accounting is resumed. | |
06138e31 | 53 | */ |
fc0be3ee | 54 | struct acct_args { |
9e97623a CT |
55 | char *fname; |
56 | }; | |
fc0be3ee | 57 | acct(p, uap, retval) |
8c7d0e2a | 58 | struct proc *p; |
fc0be3ee | 59 | struct acct_args *uap; |
8c7d0e2a | 60 | int *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 | } | |
46e4c6f8 | 74 | if (uap->fname == 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 | } |
9e7d3651 KM |
82 | NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p); |
83 | if (error = vn_open(&nd, FWRITE, 0644)) | |
d9c2f47f | 84 | return (error); |
3789a403 | 85 | vp = nd.ni_vp; |
c130850a | 86 | VOP_UNLOCK(vp); |
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 KM |
100 | * Periodically check the file system to see if accounting |
101 | * should be turned on or off. | |
06138e31 | 102 | */ |
f02cb652 CT |
103 | /* ARGSUSED */ |
104 | void | |
105 | acctwatch(a) | |
106 | void *a; | |
06138e31 | 107 | { |
c4ec2128 | 108 | struct statfs sb; |
06138e31 SL |
109 | |
110 | if (savacctp) { | |
6bcdc4f3 | 111 | (void)VFS_STATFS(savacctp->v_mount, &sb, (struct proc *)0); |
c4ec2128 | 112 | if (sb.f_bavail > acctresume * sb.f_blocks / 100) { |
06138e31 SL |
113 | acctp = savacctp; |
114 | savacctp = NULL; | |
c4ec2128 | 115 | log(LOG_NOTICE, "Accounting resumed\n"); |
1e613993 KM |
116 | } |
117 | } else { | |
118 | if (acctp == NULL) | |
c4ec2128 | 119 | return; |
1e613993 KM |
120 | (void)VFS_STATFS(acctp->v_mount, &sb, (struct proc *)0); |
121 | if (sb.f_bavail <= acctsuspend * sb.f_blocks / 100) { | |
122 | savacctp = acctp; | |
123 | acctp = NULL; | |
124 | log(LOG_NOTICE, "Accounting suspended\n"); | |
06138e31 SL |
125 | } |
126 | } | |
1e613993 | 127 | timeout(acctwatch, NULL, acctchkfreq * hz); |
c4ec2128 KM |
128 | } |
129 | ||
130 | /* | |
02cf434b KM |
131 | * This routine calculates an accounting record for a process and, |
132 | * if accounting is enabled, writes it to the accounting file. | |
c4ec2128 | 133 | */ |
fc0be3ee | 134 | acct_process(p) |
8c7d0e2a | 135 | register struct proc *p; |
c4ec2128 KM |
136 | { |
137 | register struct rusage *ru; | |
138 | struct vnode *vp; | |
1cab08e7 MT |
139 | struct timeval t, ut, st; |
140 | int i, s; | |
c4ec2128 KM |
141 | struct acct acctbuf; |
142 | register struct acct *ap = &acctbuf; | |
143 | ||
144 | if ((vp = acctp) == NULL) | |
8c7d0e2a | 145 | return (0); |
1cab08e7 | 146 | bcopy(p->p_comm, ap->ac_comm, sizeof(ap->ac_comm)); |
3789a403 | 147 | ru = &p->p_stats->p_ru; |
f02cb652 | 148 | calcru(p, &ut, &st, NULL); |
1cab08e7 | 149 | s = splclock(); |
032146e9 | 150 | t = time; |
1cab08e7 MT |
151 | splx(s); |
152 | ap->ac_utime = compress(ut.tv_sec, ut.tv_usec); | |
153 | ap->ac_stime = compress(st.tv_sec, st.tv_usec); | |
3789a403 | 154 | timevalsub(&t, &p->p_stats->p_start); |
032146e9 | 155 | ap->ac_etime = compress(t.tv_sec, t.tv_usec); |
3789a403 MK |
156 | ap->ac_btime = p->p_stats->p_start.tv_sec; |
157 | ap->ac_uid = p->p_cred->p_ruid; | |
158 | ap->ac_gid = p->p_cred->p_rgid; | |
1cab08e7 MT |
159 | t = st; |
160 | timevaladd(&t, &ut); | |
350f5463 | 161 | if (i = t.tv_sec * hz + t.tv_usec / tick) |
3789a403 | 162 | ap->ac_mem = (ru->ru_ixrss + ru->ru_idrss + ru->ru_isrss) / i; |
032146e9 SL |
163 | else |
164 | ap->ac_mem = 0; | |
01b0e233 | 165 | ap->ac_io = compress(ru->ru_inblock + ru->ru_oublock, (long)0); |
cf5ef508 | 166 | if (p->p_flag & P_CONTROLT && p->p_session->s_ttyp) |
1cab08e7 | 167 | ap->ac_tty = p->p_session->s_ttyp->t_dev; |
06138e31 SL |
168 | else |
169 | ap->ac_tty = NODEV; | |
3789a403 | 170 | ap->ac_flag = p->p_acflag; |
2881f082 | 171 | LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); |
6bcdc4f3 KM |
172 | return (vn_rdwr(UIO_WRITE, vp, (caddr_t)ap, sizeof (acctbuf), (off_t)0, |
173 | UIO_SYSSPACE, IO_UNIT|IO_APPEND, p->p_ucred, (int *)0, | |
174 | (struct proc *)0)); | |
06138e31 SL |
175 | } |
176 | ||
177 | /* | |
178 | * Produce a pseudo-floating point representation | |
179 | * with 3 bits base-8 exponent, 13 bits fraction. | |
180 | */ | |
032146e9 | 181 | compress(t, ut) |
06138e31 | 182 | register long t; |
032146e9 | 183 | long ut; |
06138e31 SL |
184 | { |
185 | register exp = 0, round = 0; | |
186 | ||
5d10e647 | 187 | t = t * AHZ; /* compiler will convert only this format to a shift */ |
032146e9 | 188 | if (ut) |
5d10e647 | 189 | t += ut / (1000000 / AHZ); |
06138e31 SL |
190 | while (t >= 8192) { |
191 | exp++; | |
192 | round = t&04; | |
193 | t >>= 3; | |
194 | } | |
195 | if (round) { | |
196 | t++; | |
197 | if (t >= 8192) { | |
198 | t >>= 3; | |
199 | exp++; | |
200 | } | |
201 | } | |
202 | return ((exp<<13) + t); | |
203 | } |