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