notify clock routines when a process requests profiling
[unix-history] / usr / src / sys / kern / kern_sysctl.c
CommitLineData
4a24f1b0
MT
1/*
2 * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
3 * All rights reserved.
4 *
dbf0c423 5 * %sccs.include.redist.c%
4a24f1b0 6 *
02ea4076 7 * @(#)kern_sysctl.c 7.22 (Berkeley) %G%
4a24f1b0
MT
8 */
9
9fbbcc07 10#include "param.h"
9fbbcc07 11#include "proc.h"
4a24f1b0 12#include "kinfo.h"
4a24f1b0
MT
13#include "ioctl.h"
14#include "tty.h"
15#include "buf.h"
318784c4 16#include "file.h"
4a24f1b0 17
32041eb1
MK
18#include "vm/vm.h"
19
20#include "kinfo_proc.h"
21
0a4df682 22#define snderr(e) { error = (e); goto release;}
318784c4 23extern int kinfo_doproc(), kinfo_rtable(), kinfo_vnode(), kinfo_file();
61ece7fc 24extern int kinfo_meter(), kinfo_loadavg(), kinfo_clockrate();
0a4df682
MT
25struct kinfo_lock kinfo_lock;
26
8b24ca5d
KM
27/* ARGSUSED */
28getkerninfo(p, uap, retval)
29 struct proc *p;
30 register struct args {
4a24f1b0
MT
31 int op;
32 char *where;
33 int *size;
34 int arg;
8b24ca5d
KM
35 } *uap;
36 int *retval;
37{
3789a403
MK
38 int bufsize; /* max size of users buffer */
39 int needed, locked, (*server)(), error = 0;
0a4df682 40
4a24f1b0
MT
41 switch (ki_type(uap->op)) {
42
43 case KINFO_PROC:
0a4df682
MT
44 server = kinfo_doproc;
45 break;
46
47 case KINFO_RT:
48 server = kinfo_rtable;
4a24f1b0
MT
49 break;
50
452737be
MT
51 case KINFO_VNODE:
52 server = kinfo_vnode;
53 break;
54
318784c4
MT
55 case KINFO_FILE:
56 server = kinfo_file;
57 break;
58
15415c71
KM
59 case KINFO_METER:
60 server = kinfo_meter;
61 break;
62
61ece7fc
KM
63 case KINFO_LOADAVG:
64 server = kinfo_loadavg;
65 break;
66
67 case KINFO_CLOCKRATE:
68 server = kinfo_clockrate;
69 break;
70
4a24f1b0 71 default:
2ed8b3ea 72 error = EINVAL;
7acc8d38
MT
73 goto done;
74 }
75 if (uap->where == NULL || uap->size == NULL) {
76 error = (*server)(uap->op, NULL, NULL, uap->arg, &needed);
77 goto done;
2ed8b3ea 78 }
aae5c50c
RC
79 if (error = copyin((caddr_t)uap->size, (caddr_t)&bufsize,
80 sizeof (bufsize)))
81 goto done;
2ed8b3ea 82 while (kinfo_lock.kl_lock) {
13bbbe63
CT
83 kinfo_lock.kl_want = 1;
84 sleep((caddr_t)&kinfo_lock, PRIBIO+1);
2ed8b3ea 85 kinfo_lock.kl_locked++;
4a24f1b0 86 }
13bbbe63 87 kinfo_lock.kl_lock = 1;
2ed8b3ea 88
7acc8d38 89 if (!useracc(uap->where, bufsize, B_WRITE))
0a4df682 90 snderr(EFAULT);
452737be
MT
91 if (server != kinfo_vnode) /* XXX */
92 vslock(uap->where, bufsize);
7acc8d38
MT
93 locked = bufsize;
94 error = (*server)(uap->op, uap->where, &bufsize, uap->arg, &needed);
452737be
MT
95 if (server != kinfo_vnode) /* XXX */
96 vsunlock(uap->where, locked, B_WRITE);
7acc8d38
MT
97 if (error == 0)
98 error = copyout((caddr_t)&bufsize,
99 (caddr_t)uap->size, sizeof (bufsize));
0a4df682 100release:
13bbbe63
CT
101 kinfo_lock.kl_lock = 0;
102 if (kinfo_lock.kl_want) {
103 kinfo_lock.kl_want = 0;
104 wakeup((caddr_t)&kinfo_lock);
105 }
7acc8d38 106done:
8b24ca5d
KM
107 if (!error)
108 *retval = needed;
109 return (error);
4a24f1b0
MT
110}
111
112/*
113 * try over estimating by 5 procs
114 */
115#define KINFO_PROCSLOP (5 * sizeof (struct kinfo_proc))
116
2ed8b3ea 117kinfo_doproc(op, where, acopysize, arg, aneeded)
13bbbe63 118 int op;
4a24f1b0 119 char *where;
13bbbe63 120 int *acopysize, arg, *aneeded;
4a24f1b0
MT
121{
122 register struct proc *p;
a65b44f0 123 register struct kinfo_proc *dp = (struct kinfo_proc *)where;
4a24f1b0 124 register needed = 0;
13bbbe63 125 int buflen = where != NULL ? *acopysize : 0;
4a24f1b0 126 int doingzomb;
7747bd3b 127 struct eproc eproc;
4a24f1b0
MT
128 int error = 0;
129
4a24f1b0
MT
130 p = allproc;
131 doingzomb = 0;
132again:
133 for (; p != NULL; p = p->p_nxt) {
02ea4076
KM
134 /*
135 * Skip embryonic processes.
136 */
137 if (p->p_stat == SIDL)
138 continue;
4a24f1b0
MT
139 /*
140 * TODO - make more efficient (see notes below).
141 * do by session.
142 */
143 switch (ki_op(op)) {
144
145 case KINFO_PROC_PID:
146 /* could do this with just a lookup */
147 if (p->p_pid != (pid_t)arg)
148 continue;
149 break;
150
151 case KINFO_PROC_PGRP:
152 /* could do this by traversing pgrp */
153 if (p->p_pgrp->pg_id != (pid_t)arg)
154 continue;
155 break;
156
157 case KINFO_PROC_TTY:
158 if ((p->p_flag&SCTTY) == 0 ||
159 p->p_session->s_ttyp == NULL ||
160 p->p_session->s_ttyp->t_dev != (dev_t)arg)
161 continue;
162 break;
163
164 case KINFO_PROC_UID:
3789a403 165 if (p->p_ucred->cr_uid != (uid_t)arg)
4a24f1b0
MT
166 continue;
167 break;
168
169 case KINFO_PROC_RUID:
3789a403 170 if (p->p_cred->p_ruid != (uid_t)arg)
4a24f1b0
MT
171 continue;
172 break;
173 }
13bbbe63 174 if (buflen >= sizeof (struct kinfo_proc)) {
32041eb1 175 fill_eproc(p, &eproc);
a65b44f0 176 if (error = copyout((caddr_t)p, &dp->kp_proc,
4a24f1b0
MT
177 sizeof (struct proc)))
178 return (error);
a65b44f0 179 if (error = copyout((caddr_t)&eproc, &dp->kp_eproc,
7747bd3b 180 sizeof (eproc)))
4a24f1b0 181 return (error);
a65b44f0 182 dp++;
4a24f1b0
MT
183 buflen -= sizeof (struct kinfo_proc);
184 }
185 needed += sizeof (struct kinfo_proc);
186 }
187 if (doingzomb == 0) {
188 p = zombproc;
189 doingzomb++;
190 goto again;
191 }
192 if (where != NULL)
a65b44f0 193 *acopysize = (caddr_t)dp - where;
0a4df682
MT
194 else
195 needed += KINFO_PROCSLOP;
4a24f1b0
MT
196 *aneeded = needed;
197
198 return (0);
199}
32041eb1
MK
200
201/*
202 * Fill in an eproc structure for the specified process.
203 */
204void
205fill_eproc(p, ep)
206 register struct proc *p;
207 register struct eproc *ep;
208{
209 register struct tty *tp;
210
211 ep->e_paddr = p;
212 ep->e_sess = p->p_pgrp->pg_session;
213 ep->e_pcred = *p->p_cred;
214 ep->e_ucred = *p->p_ucred;
13bbbe63
CT
215 if (p->p_stat == SIDL || p->p_stat == SZOMB) {
216 ep->e_vm.vm_rssize = 0;
217 ep->e_vm.vm_tsize = 0;
218 ep->e_vm.vm_dsize = 0;
219 ep->e_vm.vm_ssize = 0;
220#ifndef sparc
221 /* ep->e_vm.vm_pmap = XXX; */
222#endif
223 } else {
224 register struct vmspace *vm = p->p_vmspace;
225
226 ep->e_vm.vm_rssize = vm->vm_rssize;
227 ep->e_vm.vm_tsize = vm->vm_tsize;
228 ep->e_vm.vm_dsize = vm->vm_dsize;
229 ep->e_vm.vm_ssize = vm->vm_ssize;
230#ifndef sparc
231 ep->e_vm.vm_pmap = vm->vm_pmap;
232#endif
233 }
31c481fa
MK
234 if (p->p_pptr)
235 ep->e_ppid = p->p_pptr->p_pid;
236 else
237 ep->e_ppid = 0;
32041eb1
MK
238 ep->e_pgid = p->p_pgrp->pg_id;
239 ep->e_jobc = p->p_pgrp->pg_jobc;
240 if ((p->p_flag&SCTTY) &&
241 (tp = ep->e_sess->s_ttyp)) {
242 ep->e_tdev = tp->t_dev;
51d82109 243 ep->e_tpgid = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID;
32041eb1
MK
244 ep->e_tsess = tp->t_session;
245 } else
246 ep->e_tdev = NODEV;
247 ep->e_flag = ep->e_sess->s_ttyvp ? EPROC_CTTY : 0;
248 if (SESS_LEADER(p))
249 ep->e_flag |= EPROC_SLEADER;
250 if (p->p_wmesg)
251 strncpy(ep->e_wmesg, p->p_wmesg, WMESGLEN);
252 ep->e_xsize = ep->e_xrssize = 0;
253 ep->e_xccount = ep->e_xswrss = 0;
254}
318784c4
MT
255
256/*
257 * Get file structures.
258 */
259kinfo_file(op, where, acopysize, arg, aneeded)
13bbbe63 260 int op;
318784c4 261 register char *where;
13bbbe63 262 int *acopysize, arg, *aneeded;
318784c4
MT
263{
264 int buflen, needed, error;
265 struct file *fp;
266 char *start = where;
267
268 if (where == NULL) {
269 /*
270 * overestimate by 10 files
271 */
272 *aneeded = sizeof (filehead) +
273 (nfiles + 10) * sizeof (struct file);
274 return (0);
275 }
276 buflen = *acopysize;
277 needed = 0;
278
279 /*
280 * first copyout filehead
281 */
282 if (buflen > sizeof (filehead)) {
283 if (error = copyout((caddr_t)&filehead, where,
284 sizeof (filehead)))
285 return (error);
286 buflen -= sizeof (filehead);
287 where += sizeof (filehead);
288 }
289 needed += sizeof (filehead);
290
291 /*
292 * followed by an array of file structures
293 */
294 for (fp = filehead; fp != NULL; fp = fp->f_filef) {
295 if (buflen > sizeof (struct file)) {
296 if (error = copyout((caddr_t)fp, where,
297 sizeof (struct file)))
298 return (error);
299 buflen -= sizeof (struct file);
300 where += sizeof (struct file);
301 }
302 needed += sizeof (struct file);
303 }
304 *acopysize = where - start;
305 *aneeded = needed;
306
307 return (0);
308}