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 | * |
02cf434b | 7 | * @(#)kern_acct.c 7.18 (Berkeley) %G% |
da7c5cc6 | 8 | */ |
06138e31 | 9 | |
94368568 JB |
10 | #include "param.h" |
11 | #include "systm.h" | |
3789a403 MK |
12 | #include "namei.h" |
13 | #include "resourcevar.h" | |
556dc220 | 14 | #include "proc.h" |
8c7d0e2a KM |
15 | #include "ioctl.h" |
16 | #include "termios.h" | |
17 | #include "tty.h" | |
c4ec2128 KM |
18 | #include "vnode.h" |
19 | #include "mount.h" | |
94368568 | 20 | #include "kernel.h" |
46e4c6f8 | 21 | #include "file.h" |
94368568 | 22 | #include "acct.h" |
c4ec2128 KM |
23 | #include "syslog.h" |
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% */ | |
30 | struct timeval chk = { 15, 0 };/* frequency to check space for accounting */ | |
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 KM |
49 | /* ARGSUSED */ |
50 | sysacct(p, uap, retval) | |
51 | struct proc *p; | |
52 | struct args { | |
53 | char *fname; | |
54 | } *uap; | |
55 | int *retval; | |
06138e31 | 56 | { |
c4ec2128 | 57 | register struct vnode *vp; |
c4ec2128 KM |
58 | extern int acctwatch(); |
59 | struct vnode *oacctp; | |
8c7d0e2a | 60 | int error; |
3789a403 | 61 | struct nameidata nd; |
06138e31 | 62 | |
3789a403 | 63 | if (error = suser(p->p_ucred, &p->p_acflag)) |
d9c2f47f | 64 | return (error); |
849cbd39 KM |
65 | if (savacctp) { |
66 | acctp = savacctp; | |
67 | savacctp = NULL; | |
68 | } | |
46e4c6f8 | 69 | if (uap->fname == NULL) { |
c4ec2128 | 70 | if (vp = acctp) { |
849cbd39 | 71 | acctp = NULL; |
c4ec2128 KM |
72 | vrele(vp); |
73 | untimeout(acctwatch, (caddr_t)&chk); | |
dbba2129 | 74 | } |
d9c2f47f | 75 | return (0); |
849cbd39 | 76 | } |
3789a403 MK |
77 | nd.ni_segflg = UIO_USERSPACE; |
78 | nd.ni_dirp = uap->fname; | |
79 | if (error = vn_open(&nd, p, FWRITE, 0644)) | |
d9c2f47f | 80 | return (error); |
3789a403 | 81 | vp = nd.ni_vp; |
c4ec2128 | 82 | if (vp->v_type != VREG) { |
c4ec2128 | 83 | vrele(vp); |
d9c2f47f | 84 | return (EACCES); |
849cbd39 | 85 | } |
c4ec2128 KM |
86 | oacctp = acctp; |
87 | acctp = vp; | |
88 | if (oacctp) | |
89 | vrele(oacctp); | |
90 | acctwatch(&chk); | |
d9c2f47f | 91 | return (0); |
06138e31 SL |
92 | } |
93 | ||
06138e31 | 94 | /* |
c4ec2128 KM |
95 | * Periodically check the file system to see if accounting |
96 | * should be turned on or off. | |
06138e31 | 97 | */ |
c4ec2128 KM |
98 | acctwatch(resettime) |
99 | struct timeval *resettime; | |
06138e31 | 100 | { |
c4ec2128 | 101 | struct statfs sb; |
06138e31 SL |
102 | |
103 | if (savacctp) { | |
6bcdc4f3 | 104 | (void)VFS_STATFS(savacctp->v_mount, &sb, (struct proc *)0); |
c4ec2128 | 105 | if (sb.f_bavail > acctresume * sb.f_blocks / 100) { |
06138e31 SL |
106 | acctp = savacctp; |
107 | savacctp = NULL; | |
c4ec2128 KM |
108 | log(LOG_NOTICE, "Accounting resumed\n"); |
109 | return; | |
06138e31 SL |
110 | } |
111 | } | |
c4ec2128 | 112 | if (acctp == NULL) |
06138e31 | 113 | return; |
6bcdc4f3 | 114 | (void)VFS_STATFS(acctp->v_mount, &sb, (struct proc *)0); |
c4ec2128 | 115 | if (sb.f_bavail <= acctsuspend * sb.f_blocks / 100) { |
06138e31 SL |
116 | savacctp = acctp; |
117 | acctp = NULL; | |
c4ec2128 | 118 | log(LOG_NOTICE, "Accounting suspended\n"); |
06138e31 | 119 | } |
c4ec2128 KM |
120 | timeout(acctwatch, (caddr_t)resettime, hzto(resettime)); |
121 | } | |
122 | ||
123 | /* | |
02cf434b KM |
124 | * This routine calculates an accounting record for a process and, |
125 | * if accounting is enabled, writes it to the accounting file. | |
c4ec2128 | 126 | */ |
8c7d0e2a KM |
127 | acct(p) |
128 | register struct proc *p; | |
c4ec2128 KM |
129 | { |
130 | register struct rusage *ru; | |
131 | struct vnode *vp; | |
1cab08e7 MT |
132 | struct timeval t, ut, st; |
133 | int i, s; | |
c4ec2128 KM |
134 | struct acct acctbuf; |
135 | register struct acct *ap = &acctbuf; | |
136 | ||
137 | if ((vp = acctp) == NULL) | |
8c7d0e2a | 138 | return (0); |
1cab08e7 | 139 | bcopy(p->p_comm, ap->ac_comm, sizeof(ap->ac_comm)); |
3789a403 | 140 | ru = &p->p_stats->p_ru; |
1cab08e7 MT |
141 | s = splclock(); |
142 | ut = p->p_utime; | |
143 | st = p->p_stime; | |
032146e9 | 144 | t = time; |
1cab08e7 MT |
145 | splx(s); |
146 | ap->ac_utime = compress(ut.tv_sec, ut.tv_usec); | |
147 | ap->ac_stime = compress(st.tv_sec, st.tv_usec); | |
3789a403 | 148 | timevalsub(&t, &p->p_stats->p_start); |
032146e9 | 149 | ap->ac_etime = compress(t.tv_sec, t.tv_usec); |
3789a403 MK |
150 | ap->ac_btime = p->p_stats->p_start.tv_sec; |
151 | ap->ac_uid = p->p_cred->p_ruid; | |
152 | ap->ac_gid = p->p_cred->p_rgid; | |
1cab08e7 MT |
153 | t = st; |
154 | timevaladd(&t, &ut); | |
350f5463 | 155 | if (i = t.tv_sec * hz + t.tv_usec / tick) |
3789a403 | 156 | ap->ac_mem = (ru->ru_ixrss + ru->ru_idrss + ru->ru_isrss) / i; |
032146e9 SL |
157 | else |
158 | ap->ac_mem = 0; | |
01b0e233 | 159 | ap->ac_io = compress(ru->ru_inblock + ru->ru_oublock, (long)0); |
42ee521d | 160 | if (p->p_flag&SCTTY && p->p_session->s_ttyp) |
1cab08e7 | 161 | ap->ac_tty = p->p_session->s_ttyp->t_dev; |
06138e31 SL |
162 | else |
163 | ap->ac_tty = NODEV; | |
3789a403 | 164 | ap->ac_flag = p->p_acflag; |
6bcdc4f3 KM |
165 | return (vn_rdwr(UIO_WRITE, vp, (caddr_t)ap, sizeof (acctbuf), (off_t)0, |
166 | UIO_SYSSPACE, IO_UNIT|IO_APPEND, p->p_ucred, (int *)0, | |
167 | (struct proc *)0)); | |
06138e31 SL |
168 | } |
169 | ||
170 | /* | |
171 | * Produce a pseudo-floating point representation | |
172 | * with 3 bits base-8 exponent, 13 bits fraction. | |
173 | */ | |
032146e9 | 174 | compress(t, ut) |
06138e31 | 175 | register long t; |
032146e9 | 176 | long ut; |
06138e31 SL |
177 | { |
178 | register exp = 0, round = 0; | |
179 | ||
5d10e647 | 180 | t = t * AHZ; /* compiler will convert only this format to a shift */ |
032146e9 | 181 | if (ut) |
5d10e647 | 182 | t += ut / (1000000 / AHZ); |
06138e31 SL |
183 | while (t >= 8192) { |
184 | exp++; | |
185 | round = t&04; | |
186 | t >>= 3; | |
187 | } | |
188 | if (round) { | |
189 | t++; | |
190 | if (t >= 8192) { | |
191 | t >>= 3; | |
192 | exp++; | |
193 | } | |
194 | } | |
195 | return ((exp<<13) + t); | |
196 | } |