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