adding GNU dc ("desk calculator")
[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 *
33 * @(#)kern_kinfo.c 7.17 (Berkeley) 6/26/91
34 */
35
36#include "param.h"
37#include "proc.h"
38#include "kinfo.h"
39#include "ioctl.h"
40#include "tty.h"
41#include "buf.h"
42#include "file.h"
43
44#include "vm/vm.h"
45
46#include "kinfo_proc.h"
47
48#define snderr(e) { error = (e); goto release;}
49extern int kinfo_doproc(), kinfo_rtable(), kinfo_vnode(), kinfo_file();
50struct kinfo_lock kinfo_lock;
51
52/* ARGSUSED */
53getkerninfo(p, uap, retval)
54 struct proc *p;
55 register struct args {
56 int op;
57 char *where;
58 int *size;
59 int arg;
60 } *uap;
61 int *retval;
62{
63
64 int bufsize; /* max size of users buffer */
65 int needed, locked, (*server)(), error = 0;
66
67 if (error = copyin((caddr_t)uap->size, (caddr_t)&bufsize,
68 sizeof (bufsize)))
69 goto done;
70
71 switch (ki_type(uap->op)) {
72
73 case KINFO_PROC:
74 server = kinfo_doproc;
75 break;
76
77 case KINFO_RT:
78 server = kinfo_rtable;
79 break;
80
81 case KINFO_VNODE:
82 server = kinfo_vnode;
83 break;
84
85 case KINFO_FILE:
86 server = kinfo_file;
87 break;
88
89 default:
90 error = EINVAL;
91 goto done;
92 }
93 if (uap->where == NULL || uap->size == NULL) {
94 error = (*server)(uap->op, NULL, NULL, uap->arg, &needed);
95 goto done;
96 }
97 while (kinfo_lock.kl_lock) {
98 kinfo_lock.kl_want++;
99 sleep(&kinfo_lock, PRIBIO+1);
100 kinfo_lock.kl_want--;
101 kinfo_lock.kl_locked++;
102 }
103 kinfo_lock.kl_lock++;
104
105 if (!useracc(uap->where, bufsize, B_WRITE))
106 snderr(EFAULT);
107 if (server != kinfo_vnode) /* XXX */
108 vslock(uap->where, bufsize);
109 locked = bufsize;
110 error = (*server)(uap->op, uap->where, &bufsize, uap->arg, &needed);
111 if (server != kinfo_vnode) /* XXX */
112 vsunlock(uap->where, locked, B_WRITE);
113 if (error == 0)
114 error = copyout((caddr_t)&bufsize,
115 (caddr_t)uap->size, sizeof (bufsize));
116release:
117 kinfo_lock.kl_lock--;
118 if (kinfo_lock.kl_want)
119 wakeup(&kinfo_lock);
120done:
121 if (!error)
122 *retval = needed;
123 return (error);
124}
125
126/*
127 * try over estimating by 5 procs
128 */
129#define KINFO_PROCSLOP (5 * sizeof (struct kinfo_proc))
130
131kinfo_doproc(op, where, acopysize, arg, aneeded)
132 char *where;
133 int *acopysize, *aneeded;
134{
135 register struct proc *p;
136 register struct kinfo_proc *dp = (struct kinfo_proc *)where;
137 register needed = 0;
138 int buflen;
139 int doingzomb;
140 struct eproc eproc;
141 int error = 0;
142
143 if (where != NULL)
144 buflen = *acopysize;
145
146 p = allproc;
147 doingzomb = 0;
148again:
149 for (; p != NULL; p = p->p_nxt) {
150 /*
151 * TODO - make more efficient (see notes below).
152 * do by session.
153 */
154 switch (ki_op(op)) {
155
156 case KINFO_PROC_PID:
157 /* could do this with just a lookup */
158 if (p->p_pid != (pid_t)arg)
159 continue;
160 break;
161
162 case KINFO_PROC_PGRP:
163 /* could do this by traversing pgrp */
164 if (p->p_pgrp->pg_id != (pid_t)arg)
165 continue;
166 break;
167
168 case KINFO_PROC_TTY:
169 if ((p->p_flag&SCTTY) == 0 ||
170 p->p_session->s_ttyp == NULL ||
171 p->p_session->s_ttyp->t_dev != (dev_t)arg)
172 continue;
173 break;
174
175 case KINFO_PROC_UID:
176 if (p->p_ucred->cr_uid != (uid_t)arg)
177 continue;
178 break;
179
180 case KINFO_PROC_RUID:
181 if (p->p_cred->p_ruid != (uid_t)arg)
182 continue;
183 break;
184 }
185 if (where != NULL && buflen >= sizeof (struct kinfo_proc)) {
186 fill_eproc(p, &eproc);
187 if (error = copyout((caddr_t)p, &dp->kp_proc,
188 sizeof (struct proc)))
189 return (error);
190 if (error = copyout((caddr_t)&eproc, &dp->kp_eproc,
191 sizeof (eproc)))
192 return (error);
193 dp++;
194 buflen -= sizeof (struct kinfo_proc);
195 }
196 needed += sizeof (struct kinfo_proc);
197 }
198 if (doingzomb == 0) {
199 p = zombproc;
200 doingzomb++;
201 goto again;
202 }
203 if (where != NULL)
204 *acopysize = (caddr_t)dp - where;
205 else
206 needed += KINFO_PROCSLOP;
207 *aneeded = needed;
208
209 return (0);
210}
211
212/*
213 * Fill in an eproc structure for the specified process.
214 */
215void
216fill_eproc(p, ep)
217 register struct proc *p;
218 register struct eproc *ep;
219{
220 register struct tty *tp;
221
222 ep->e_paddr = p;
223 ep->e_sess = p->p_pgrp->pg_session;
224 ep->e_pcred = *p->p_cred;
225 ep->e_ucred = *p->p_ucred;
226 ep->e_vm = *p->p_vmspace;
227 if (p->p_pptr)
228 ep->e_ppid = p->p_pptr->p_pid;
229 else
230 ep->e_ppid = 0;
231 ep->e_pgid = p->p_pgrp->pg_id;
232 ep->e_jobc = p->p_pgrp->pg_jobc;
233 if ((p->p_flag&SCTTY) &&
234 (tp = ep->e_sess->s_ttyp)) {
235 ep->e_tdev = tp->t_dev;
236 ep->e_tpgid = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID;
237 ep->e_tsess = tp->t_session;
238 } else
239 ep->e_tdev = NODEV;
240 ep->e_flag = ep->e_sess->s_ttyvp ? EPROC_CTTY : 0;
241 if (SESS_LEADER(p))
242 ep->e_flag |= EPROC_SLEADER;
243 if (p->p_wmesg)
244 strncpy(ep->e_wmesg, p->p_wmesg, WMESGLEN);
245 ep->e_xsize = ep->e_xrssize = 0;
246 ep->e_xccount = ep->e_xswrss = 0;
247}
248
249/*
250 * Get file structures.
251 */
252kinfo_file(op, where, acopysize, arg, aneeded)
253 register char *where;
254 int *acopysize, *aneeded;
255{
256 int buflen, needed, error;
257 struct file *fp;
258 char *start = where;
259
260 if (where == NULL) {
261 /*
262 * overestimate by 10 files
263 */
264 *aneeded = sizeof (filehead) +
265 (nfiles + 10) * sizeof (struct file);
266 return (0);
267 }
268 buflen = *acopysize;
269 needed = 0;
270
271 /*
272 * first copyout filehead
273 */
274 if (buflen > sizeof (filehead)) {
275 if (error = copyout((caddr_t)&filehead, where,
276 sizeof (filehead)))
277 return (error);
278 buflen -= sizeof (filehead);
279 where += sizeof (filehead);
280 }
281 needed += sizeof (filehead);
282
283 /*
284 * followed by an array of file structures
285 */
286 for (fp = filehead; fp != NULL; fp = fp->f_filef) {
287 if (buflen > sizeof (struct file)) {
288 if (error = copyout((caddr_t)fp, where,
289 sizeof (struct file)))
290 return (error);
291 buflen -= sizeof (struct file);
292 where += sizeof (struct file);
293 }
294 needed += sizeof (struct file);
295 }
296 *acopysize = where - start;
297 *aneeded = needed;
298
299 return (0);
300}