xref: /original-bsd/sys/kern/kern_acct.c (revision c47935e1)
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 are permitted
6  * provided that the above copyright notice and this paragraph are
7  * duplicated in all such forms and that any documentation,
8  * advertising materials, and other materials related to such
9  * distribution and use acknowledge that the software was developed
10  * by the University of California, Berkeley.  The name of the
11  * University may not be used to endorse or promote products derived
12  * from this software without specific prior written permission.
13  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  *
17  *	@(#)kern_acct.c	7.5 (Berkeley) 05/09/89
18  */
19 
20 #include "param.h"
21 #include "systm.h"
22 #include "user.h"
23 #include "vnode.h"
24 #include "mount.h"
25 #include "kernel.h"
26 #include "acct.h"
27 #include "uio.h"
28 #include "syslog.h"
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% */
35 struct	timeval chk = { 15, 0 };/* frequency to check space for accounting */
36 
37 /*
38  * SHOULD REPLACE THIS WITH A DRIVER THAT CAN BE READ TO SIMPLIFY.
39  */
40 struct	vnode *acctp;
41 struct	vnode *savacctp;
42 
43 /*
44  * Perform process accounting functions.
45  */
46 sysacct()
47 {
48 	register struct vnode *vp;
49 	register struct a {
50 		char	*fname;
51 	} *uap = (struct a *)u.u_ap;
52 	register struct nameidata *ndp = &u.u_nd;
53 	extern int acctwatch();
54 	struct vnode *oacctp;
55 
56 	if (u.u_error = suser(u.u_cred, &u.u_acflag))
57 		return;
58 	if (savacctp) {
59 		acctp = savacctp;
60 		savacctp = NULL;
61 	}
62 	if (uap->fname==NULL) {
63 		if (vp = acctp) {
64 			acctp = NULL;
65 			vrele(vp);
66 			untimeout(acctwatch, (caddr_t)&chk);
67 		}
68 		return;
69 	}
70 	ndp->ni_nameiop = LOOKUP | FOLLOW;
71 	ndp->ni_segflg = UIO_USERSPACE;
72 	ndp->ni_dirp = uap->fname;
73 	if (u.u_error = namei(ndp))
74 		return;
75 	vp = ndp->ni_vp;
76 	if (vp->v_type != VREG) {
77 		u.u_error = EACCES;
78 		vrele(vp);
79 		return;
80 	}
81 	if (vp->v_mount->m_flag & M_RDONLY) {
82 		u.u_error = EROFS;
83 		vrele(vp);
84 		return;
85 	}
86 	oacctp = acctp;
87 	acctp = vp;
88 	if (oacctp)
89 		vrele(oacctp);
90 	acctwatch(&chk);
91 }
92 
93 /*
94  * Periodically check the file system to see if accounting
95  * should be turned on or off.
96  */
97 acctwatch(resettime)
98 	struct timeval *resettime;
99 {
100 	struct statfs sb;
101 
102 	if (savacctp) {
103 		(void)VFS_STATFS(savacctp->v_mount, &sb);
104 		if (sb.f_bavail > acctresume * sb.f_blocks / 100) {
105 			acctp = savacctp;
106 			savacctp = NULL;
107 			log(LOG_NOTICE, "Accounting resumed\n");
108 			return;
109 		}
110 	}
111 	if (acctp == NULL)
112 		return;
113 	(void)VFS_STATFS(acctp->v_mount, &sb);
114 	if (sb.f_bavail <= acctsuspend * sb.f_blocks / 100) {
115 		savacctp = acctp;
116 		acctp = NULL;
117 		log(LOG_NOTICE, "Accounting suspended\n");
118 	}
119 	timeout(acctwatch, (caddr_t)resettime, hzto(resettime));
120 }
121 
122 /*
123  * On exit, write a record on the accounting file.
124  */
125 acct()
126 {
127 	register struct rusage *ru;
128 	struct vnode *vp;
129 	struct timeval t;
130 	int i;
131 	struct acct acctbuf;
132 	register struct acct *ap = &acctbuf;
133 
134 	if ((vp = acctp) == NULL)
135 		return;
136 	bcopy(u.u_comm, ap->ac_comm, sizeof(ap->ac_comm));
137 	ru = &u.u_ru;
138 	ap->ac_utime = compress(ru->ru_utime.tv_sec, ru->ru_utime.tv_usec);
139 	ap->ac_stime = compress(ru->ru_stime.tv_sec, ru->ru_stime.tv_usec);
140 	t = time;
141 	timevalsub(&t, &u.u_start);
142 	ap->ac_etime = compress(t.tv_sec, t.tv_usec);
143 	ap->ac_btime = u.u_start.tv_sec;
144 	ap->ac_uid = u.u_ruid;
145 	ap->ac_gid = u.u_rgid;
146 	t = ru->ru_stime;
147 	timevaladd(&t, &ru->ru_utime);
148 	if (i = t.tv_sec * hz + t.tv_usec / tick)
149 		ap->ac_mem = (ru->ru_ixrss+ru->ru_idrss+ru->ru_isrss) / i;
150 	else
151 		ap->ac_mem = 0;
152 	ap->ac_mem >>= CLSIZELOG2;
153 	ap->ac_io = compress(ru->ru_inblock + ru->ru_oublock, (long)0);
154 	if (u.u_ttyp)
155 		ap->ac_tty = u.u_ttyd;
156 	else
157 		ap->ac_tty = NODEV;
158 	ap->ac_flag = u.u_acflag;
159 	u.u_error = vn_rdwr(UIO_WRITE, vp, (caddr_t)ap, sizeof (acctbuf),
160 		(off_t)0, UIO_SYSSPACE, IO_UNIT|IO_APPEND, u.u_cred, (int *)0);
161 }
162 
163 /*
164  * Produce a pseudo-floating point representation
165  * with 3 bits base-8 exponent, 13 bits fraction.
166  */
167 compress(t, ut)
168 	register long t;
169 	long ut;
170 {
171 	register exp = 0, round = 0;
172 
173 	t = t * AHZ;  /* compiler will convert only this format to a shift */
174 	if (ut)
175 		t += ut / (1000000 / AHZ);
176 	while (t >= 8192) {
177 		exp++;
178 		round = t&04;
179 		t >>= 3;
180 	}
181 	if (round) {
182 		t++;
183 		if (t >= 8192) {
184 			t >>= 3;
185 			exp++;
186 		}
187 	}
188 	return ((exp<<13) + t);
189 }
190