xref: /386bsd/usr/src/kernel/kern/kinfo.c (revision a2142627)
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