This commit was manufactured by cvs2svn to create tag 'FreeBSD-release/1.0'.
[unix-history] / sys / kern / kern_kinfo.c
CommitLineData
15637ed4
RG
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, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
78ed81a3 33 * from: @(#)kern_kinfo.c 7.17 (Berkeley) 6/26/91
34 * $Id$
15637ed4
RG
35 */
36
37#include "param.h"
38#include "proc.h"
39#include "kinfo.h"
40#include "ioctl.h"
41#include "tty.h"
42#include "buf.h"
43#include "file.h"
44
45#include "vm/vm.h"
46
47#include "kinfo_proc.h"
48
49#define snderr(e) { error = (e); goto release;}
50extern int kinfo_doproc(), kinfo_rtable(), kinfo_vnode(), kinfo_file();
51struct kinfo_lock kinfo_lock;
52
78ed81a3 53struct getkerninfo_args {
54 int op;
55 char *where;
56 int *size;
57 int arg;
58};
59
15637ed4
RG
60/* ARGSUSED */
61getkerninfo(p, uap, retval)
62 struct proc *p;
78ed81a3 63 register struct getkerninfo_args *uap;
15637ed4
RG
64 int *retval;
65{
66
67 int bufsize; /* max size of users buffer */
68 int needed, locked, (*server)(), error = 0;
69
70 if (error = copyin((caddr_t)uap->size, (caddr_t)&bufsize,
71 sizeof (bufsize)))
72 goto done;
73
74 switch (ki_type(uap->op)) {
75
76 case KINFO_PROC:
77 server = kinfo_doproc;
78 break;
79
80 case KINFO_RT:
81 server = kinfo_rtable;
82 break;
83
84 case KINFO_VNODE:
85 server = kinfo_vnode;
86 break;
87
88 case KINFO_FILE:
89 server = kinfo_file;
90 break;
91
92 default:
93 error = EINVAL;
94 goto done;
95 }
96 if (uap->where == NULL || uap->size == NULL) {
97 error = (*server)(uap->op, NULL, NULL, uap->arg, &needed);
98 goto done;
99 }
100 while (kinfo_lock.kl_lock) {
101 kinfo_lock.kl_want++;
102 sleep(&kinfo_lock, PRIBIO+1);
103 kinfo_lock.kl_want--;
104 kinfo_lock.kl_locked++;
105 }
106 kinfo_lock.kl_lock++;
107
108 if (!useracc(uap->where, bufsize, B_WRITE))
109 snderr(EFAULT);
110 if (server != kinfo_vnode) /* XXX */
111 vslock(uap->where, bufsize);
112 locked = bufsize;
113 error = (*server)(uap->op, uap->where, &bufsize, uap->arg, &needed);
114 if (server != kinfo_vnode) /* XXX */
115 vsunlock(uap->where, locked, B_WRITE);
116 if (error == 0)
117 error = copyout((caddr_t)&bufsize,
118 (caddr_t)uap->size, sizeof (bufsize));
119release:
120 kinfo_lock.kl_lock--;
121 if (kinfo_lock.kl_want)
122 wakeup(&kinfo_lock);
123done:
124 if (!error)
125 *retval = needed;
126 return (error);
127}
128
129/*
130 * try over estimating by 5 procs
131 */
132#define KINFO_PROCSLOP (5 * sizeof (struct kinfo_proc))
133
134kinfo_doproc(op, where, acopysize, arg, aneeded)
135 char *where;
136 int *acopysize, *aneeded;
137{
138 register struct proc *p;
139 register struct kinfo_proc *dp = (struct kinfo_proc *)where;
140 register needed = 0;
141 int buflen;
142 int doingzomb;
143 struct eproc eproc;
144 int error = 0;
145
146 if (where != NULL)
147 buflen = *acopysize;
148
149 p = allproc;
150 doingzomb = 0;
151again:
152 for (; p != NULL; p = p->p_nxt) {
153 /*
154 * TODO - make more efficient (see notes below).
155 * do by session.
156 */
157 switch (ki_op(op)) {
158
159 case KINFO_PROC_PID:
160 /* could do this with just a lookup */
161 if (p->p_pid != (pid_t)arg)
162 continue;
163 break;
164
165 case KINFO_PROC_PGRP:
166 /* could do this by traversing pgrp */
167 if (p->p_pgrp->pg_id != (pid_t)arg)
168 continue;
169 break;
170
171 case KINFO_PROC_TTY:
172 if ((p->p_flag&SCTTY) == 0 ||
173 p->p_session->s_ttyp == NULL ||
174 p->p_session->s_ttyp->t_dev != (dev_t)arg)
175 continue;
176 break;
177
178 case KINFO_PROC_UID:
179 if (p->p_ucred->cr_uid != (uid_t)arg)
180 continue;
181 break;
182
183 case KINFO_PROC_RUID:
184 if (p->p_cred->p_ruid != (uid_t)arg)
185 continue;
186 break;
187 }
188 if (where != NULL && buflen >= sizeof (struct kinfo_proc)) {
189 fill_eproc(p, &eproc);
190 if (error = copyout((caddr_t)p, &dp->kp_proc,
191 sizeof (struct proc)))
192 return (error);
193 if (error = copyout((caddr_t)&eproc, &dp->kp_eproc,
194 sizeof (eproc)))
195 return (error);
196 dp++;
197 buflen -= sizeof (struct kinfo_proc);
198 }
199 needed += sizeof (struct kinfo_proc);
200 }
201 if (doingzomb == 0) {
202 p = zombproc;
203 doingzomb++;
204 goto again;
205 }
206 if (where != NULL)
207 *acopysize = (caddr_t)dp - where;
208 else
209 needed += KINFO_PROCSLOP;
210 *aneeded = needed;
211
212 return (0);
213}
214
215/*
216 * Fill in an eproc structure for the specified process.
217 */
218void
219fill_eproc(p, ep)
220 register struct proc *p;
221 register struct eproc *ep;
222{
223 register struct tty *tp;
224
225 ep->e_paddr = p;
226 ep->e_sess = p->p_pgrp->pg_session;
227 ep->e_pcred = *p->p_cred;
228 ep->e_ucred = *p->p_ucred;
229 ep->e_vm = *p->p_vmspace;
230 if (p->p_pptr)
231 ep->e_ppid = p->p_pptr->p_pid;
232 else
233 ep->e_ppid = 0;
234 ep->e_pgid = p->p_pgrp->pg_id;
235 ep->e_jobc = p->p_pgrp->pg_jobc;
236 if ((p->p_flag&SCTTY) &&
237 (tp = ep->e_sess->s_ttyp)) {
238 ep->e_tdev = tp->t_dev;
239 ep->e_tpgid = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID;
240 ep->e_tsess = tp->t_session;
241 } else
242 ep->e_tdev = NODEV;
243 ep->e_flag = ep->e_sess->s_ttyvp ? EPROC_CTTY : 0;
244 if (SESS_LEADER(p))
245 ep->e_flag |= EPROC_SLEADER;
246 if (p->p_wmesg)
247 strncpy(ep->e_wmesg, p->p_wmesg, WMESGLEN);
248 ep->e_xsize = ep->e_xrssize = 0;
249 ep->e_xccount = ep->e_xswrss = 0;
250}
251
252/*
253 * Get file structures.
254 */
255kinfo_file(op, where, acopysize, arg, aneeded)
256 register char *where;
257 int *acopysize, *aneeded;
258{
259 int buflen, needed, error;
260 struct file *fp;
261 char *start = where;
262
263 if (where == NULL) {
264 /*
265 * overestimate by 10 files
266 */
267 *aneeded = sizeof (filehead) +
268 (nfiles + 10) * sizeof (struct file);
269 return (0);
270 }
271 buflen = *acopysize;
272 needed = 0;
273
274 /*
275 * first copyout filehead
276 */
277 if (buflen > sizeof (filehead)) {
278 if (error = copyout((caddr_t)&filehead, where,
279 sizeof (filehead)))
280 return (error);
281 buflen -= sizeof (filehead);
282 where += sizeof (filehead);
283 }
284 needed += sizeof (filehead);
285
286 /*
287 * followed by an array of file structures
288 */
289 for (fp = filehead; fp != NULL; fp = fp->f_filef) {
290 if (buflen > sizeof (struct file)) {
291 if (error = copyout((caddr_t)fp, where,
292 sizeof (struct file)))
293 return (error);
294 buflen -= sizeof (struct file);
295 where += sizeof (struct file);
296 }
297 needed += sizeof (struct file);
298 }
299 *acopysize = where - start;
300 *aneeded = needed;
301
302 return (0);
303}