xref: /freebsd/sys/kern/kern_sysctl.c (revision 17ee9d00bc1ae1e598c38f25826f861e4bc6c3ce)
1 /*-
2  * Copyright (c) 1982, 1986, 1989, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Mike Karels at Berkeley Software Design, Inc.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *	This product includes software developed by the University of
19  *	California, Berkeley and its contributors.
20  * 4. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  *
36  *	@(#)kern_sysctl.c	8.4 (Berkeley) 4/14/94
37  * $Id: kern_sysctl.c,v 1.21 1994/12/28 06:15:08 davidg Exp $
38  */
39 
40 /*
41  * sysctl system call.
42  */
43 
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/kernel.h>
47 #include <sys/malloc.h>
48 #include <sys/proc.h>
49 #include <sys/file.h>
50 #include <sys/vnode.h>
51 #include <sys/unistd.h>
52 #include <sys/buf.h>
53 #include <sys/ioctl.h>
54 #include <sys/tty.h>
55 #include <vm/vm.h>
56 #include <sys/sysctl.h>
57 
58 #ifdef DEBUG
59 static sysctlfn debug_sysctl;
60 #endif
61 
62 /*
63  * Locking and stats
64  */
65 static struct sysctl_lock {
66 	int	sl_lock;
67 	int	sl_want;
68 	int	sl_locked;
69 } memlock;
70 
71 struct sysctl_args {
72 	int	*name;
73 	u_int	namelen;
74 	void	*old;
75 	size_t	*oldlenp;
76 	void	*new;
77 	size_t	newlen;
78 };
79 
80 int
81 __sysctl(p, uap, retval)
82 	struct proc *p;
83 	register struct sysctl_args *uap;
84 	int *retval;
85 {
86 	int error, dolock = 1;
87 	u_int savelen = 0, oldlen = 0;
88 	sysctlfn *fn;
89 	int name[CTL_MAXNAME];
90 
91 	if (uap->new != NULL && (error = suser(p->p_ucred, &p->p_acflag)))
92 		return (error);
93 	/*
94 	 * all top-level sysctl names are non-terminal
95 	 */
96 	if (uap->namelen > CTL_MAXNAME || uap->namelen < 2)
97 		return (EINVAL);
98  	error = copyin(uap->name, &name, uap->namelen * sizeof(int));
99  	if (error)
100 		return (error);
101 
102 	switch (name[0]) {
103 	case CTL_KERN:
104 		fn = kern_sysctl;
105 		if (name[1] != KERN_VNODE)      /* XXX */
106 			dolock = 0;
107 		break;
108 	case CTL_HW:
109 		fn = hw_sysctl;
110 		break;
111 	case CTL_VM:
112 		fn = vm_sysctl;
113 		break;
114 	case CTL_NET:
115 		fn = net_sysctl;
116 		break;
117 	case CTL_FS:
118 		fn = fs_sysctl;
119 		break;
120 	case CTL_MACHDEP:
121 		fn = cpu_sysctl;
122 		break;
123 #ifdef DEBUG
124 	case CTL_DEBUG:
125 		fn = debug_sysctl;
126 		break;
127 #endif
128 	default:
129 		return (EOPNOTSUPP);
130 	}
131 
132 	if (uap->oldlenp &&
133 	    (error = copyin(uap->oldlenp, &oldlen, sizeof(oldlen))))
134 		return (error);
135 	if (uap->old != NULL) {
136 		if (!useracc(uap->old, oldlen, B_WRITE))
137 			return (EFAULT);
138 		while (memlock.sl_lock) {
139 			memlock.sl_want = 1;
140 			(void) tsleep((caddr_t)&memlock, PRIBIO+1, "sysctl", 0);
141 			memlock.sl_locked++;
142 		}
143 		memlock.sl_lock = 1;
144 		if (dolock)
145 			vslock(uap->old, oldlen);
146 		savelen = oldlen;
147 	}
148 	error = (*fn)(name + 1, uap->namelen - 1, uap->old, &oldlen,
149 	    uap->new, uap->newlen, p);
150 	if (uap->old != NULL) {
151 		if (dolock)
152 			vsunlock(uap->old, savelen, B_WRITE);
153 		memlock.sl_lock = 0;
154 		if (memlock.sl_want) {
155 			memlock.sl_want = 0;
156 			wakeup((caddr_t)&memlock);
157 		}
158 	}
159 	if (error)
160 		return (error);
161 	if (uap->oldlenp)
162 		error = copyout(&oldlen, uap->oldlenp, sizeof(oldlen));
163 	*retval = oldlen;
164 	return (0);
165 }
166 
167 /*
168  * Attributes stored in the kernel.
169  */
170 char hostname[MAXHOSTNAMELEN];
171 int hostnamelen;
172 char domainname[MAXHOSTNAMELEN];
173 int domainnamelen;
174 long hostid;
175 int securelevel = -1;
176 char kernelname[MAXPATHLEN] = "/kernel";	/* XXX bloat */
177 extern int vfs_update_wakeup;
178 extern int vfs_update_interval;
179 extern int osreldate;
180 
181 /*
182  * kernel related system variables.
183  */
184 int
185 kern_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
186 	int *name;
187 	u_int namelen;
188 	void *oldp;
189 	size_t *oldlenp;
190 	void *newp;
191 	size_t newlen;
192 	struct proc *p;
193 {
194 	int error, level, inthostid;
195 	extern char ostype[], osrelease[];
196 
197 	/* all sysctl names at this level are terminal */
198 	if (namelen != 1 && !(name[0] == KERN_PROC || name[0] == KERN_PROF
199 			      || name[0] == KERN_NTP_PLL))
200 		return (ENOTDIR);		/* overloaded */
201 
202 	switch (name[0]) {
203 	case KERN_OSTYPE:
204 		return (sysctl_rdstring(oldp, oldlenp, newp, ostype));
205 	case KERN_OSRELEASE:
206 		return (sysctl_rdstring(oldp, oldlenp, newp, osrelease));
207 	case KERN_OSREV:
208 		return (sysctl_rdint(oldp, oldlenp, newp, BSD));
209 	case KERN_VERSION:
210 		return (sysctl_rdstring(oldp, oldlenp, newp, version));
211 	case KERN_OSRELDATE:
212 		return (sysctl_rdint(oldp, oldlenp, newp, osreldate));
213 	case KERN_BOOTFILE:
214 		return (sysctl_string(oldp, oldlenp, newp, newlen,
215 				      kernelname, sizeof kernelname));
216 	case KERN_MAXVNODES:
217 		return(sysctl_int(oldp, oldlenp, newp, newlen, &desiredvnodes));
218 	case KERN_MAXPROC:
219 		return (sysctl_int(oldp, oldlenp, newp, newlen, &maxproc));
220 	case KERN_MAXPROCPERUID:
221 		return (sysctl_int(oldp, oldlenp, newp, newlen, &maxprocperuid));
222 	case KERN_MAXFILES:
223 		return (sysctl_int(oldp, oldlenp, newp, newlen, &maxfiles));
224 	case KERN_MAXFILESPERPROC:
225 		return (sysctl_int(oldp, oldlenp, newp, newlen, &maxfilesperproc));
226 	case KERN_UPDATEINTERVAL:
227 		/*
228 		 * NB: this simple-minded approach only works because
229 		 * `tsleep' takes a timeout argument of 0 as meaning
230 		 * `no timeout'.
231 		 */
232 		error = sysctl_int(oldp, oldlenp, newp, newlen,
233 				   &vfs_update_interval);
234 		if(!error) {
235 			wakeup(&vfs_update_wakeup);
236 		}
237 		return error;
238 	case KERN_ARGMAX:
239 		return (sysctl_rdint(oldp, oldlenp, newp, ARG_MAX));
240 	case KERN_SECURELVL:
241 		level = securelevel;
242 		if ((error = sysctl_int(oldp, oldlenp, newp, newlen, &level)) ||
243 		    newp == NULL)
244 			return (error);
245 		if (level < securelevel && p->p_pid != 1)
246 			return (EPERM);
247 		securelevel = level;
248 		return (0);
249 	case KERN_HOSTNAME:
250 		error = sysctl_string(oldp, oldlenp, newp, newlen,
251 		    hostname, sizeof(hostname));
252 		if (newp && !error)
253 			hostnamelen = newlen;
254 		return (error);
255 	case KERN_DOMAINNAME:
256 		error = sysctl_string(oldp, oldlenp, newp, newlen,
257 		    domainname, sizeof(domainname));
258 		if (newp && !error)
259 			domainnamelen = newlen;
260 		return (error);
261 	case KERN_HOSTID:
262 		inthostid = hostid;  /* XXX assumes sizeof long <= sizeof int */
263 		error =  sysctl_int(oldp, oldlenp, newp, newlen, &inthostid);
264 		hostid = inthostid;
265 		return (error);
266 	case KERN_CLOCKRATE:
267 		return (sysctl_clockrate(oldp, oldlenp));
268 	case KERN_BOOTTIME:
269 		return (sysctl_rdstruct(oldp, oldlenp, newp, &boottime,
270 		    sizeof(struct timeval)));
271 	case KERN_VNODE:
272 		return (sysctl_vnode(oldp, oldlenp));
273 	case KERN_PROC:
274 		return (sysctl_doproc(name + 1, namelen - 1, oldp, oldlenp));
275 	case KERN_FILE:
276 		return (sysctl_file(oldp, oldlenp));
277 #ifdef GPROF
278 	case KERN_PROF:
279 		return (sysctl_doprof(name + 1, namelen - 1, oldp, oldlenp,
280 		    newp, newlen));
281 #endif
282 	case KERN_POSIX1:
283 		return (sysctl_rdint(oldp, oldlenp, newp, _POSIX_VERSION));
284 	case KERN_NGROUPS:
285 		return (sysctl_rdint(oldp, oldlenp, newp, NGROUPS_MAX));
286 	case KERN_JOB_CONTROL:
287 		return (sysctl_rdint(oldp, oldlenp, newp, 1));
288 	case KERN_SAVED_IDS:
289 #ifdef _POSIX_SAVED_IDS
290 		return (sysctl_rdint(oldp, oldlenp, newp, 1));
291 #else
292 		return (sysctl_rdint(oldp, oldlenp, newp, 0));
293 #endif
294 	case KERN_NTP_PLL:
295 		return (ntp_sysctl(name + 1, namelen - 1, oldp, oldlenp,
296 				   newp, newlen, p));
297 	default:
298 		return (EOPNOTSUPP);
299 	}
300 	/* NOTREACHED */
301 }
302 
303 /*
304  * hardware related system variables.
305  */
306 int
307 hw_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
308 	int *name;
309 	u_int namelen;
310 	void *oldp;
311 	size_t *oldlenp;
312 	void *newp;
313 	size_t newlen;
314 	struct proc *p;
315 {
316 	extern char machine[], cpu_model[];
317 	extern int hw_float;
318 
319 	/* almost all sysctl names at this level are terminal */
320 	if (namelen != 1 && name[0] != HW_DEVCONF)
321 		return (ENOTDIR);		/* overloaded */
322 
323 	switch (name[0]) {
324 	case HW_MACHINE:
325 		return (sysctl_rdstring(oldp, oldlenp, newp, machine));
326 	case HW_MODEL:
327 		return (sysctl_rdstring(oldp, oldlenp, newp, cpu_model));
328 	case HW_NCPU:
329 		return (sysctl_rdint(oldp, oldlenp, newp, 1));	/* XXX */
330 	case HW_BYTEORDER:
331 		return (sysctl_rdint(oldp, oldlenp, newp, BYTE_ORDER));
332 	case HW_PHYSMEM:
333 		return (sysctl_rdint(oldp, oldlenp, newp, ctob(physmem)));
334 	case HW_USERMEM:
335 		return (sysctl_rdint(oldp, oldlenp, newp,
336 		    ctob(physmem - cnt.v_wire_count)));
337 	case HW_PAGESIZE:
338 		return (sysctl_rdint(oldp, oldlenp, newp, PAGE_SIZE));
339 	case HW_FLOATINGPT:
340 		return (sysctl_rdint(oldp, oldlenp, newp, hw_float));
341 	case HW_DEVCONF:
342 		return (dev_sysctl(name + 1, namelen - 1, oldp, oldlenp,
343 				   newp, newlen, p));
344 	default:
345 		return (EOPNOTSUPP);
346 	}
347 	/* NOTREACHED */
348 }
349 
350 #ifdef DEBUG
351 /*
352  * Debugging related system variables.
353  */
354 struct ctldebug debug0, debug1, debug2, debug3, debug4;
355 struct ctldebug debug5, debug6, debug7, debug8, debug9;
356 struct ctldebug debug10, debug11, debug12, debug13, debug14;
357 struct ctldebug debug15, debug16, debug17, debug18, debug19;
358 static struct ctldebug *debugvars[CTL_DEBUG_MAXID] = {
359 	&debug0, &debug1, &debug2, &debug3, &debug4,
360 	&debug5, &debug6, &debug7, &debug8, &debug9,
361 	&debug10, &debug11, &debug12, &debug13, &debug14,
362 	&debug15, &debug16, &debug17, &debug18, &debug19,
363 };
364 static int
365 debug_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
366 	int *name;
367 	u_int namelen;
368 	void *oldp;
369 	size_t *oldlenp;
370 	void *newp;
371 	size_t newlen;
372 	struct proc *p;
373 {
374 	struct ctldebug *cdp;
375 
376 	/* all sysctl names at this level are name and field */
377 	if (namelen != 2)
378 		return (ENOTDIR);		/* overloaded */
379 	cdp = debugvars[name[0]];
380 	if (cdp->debugname == 0)
381 		return (EOPNOTSUPP);
382 	switch (name[1]) {
383 	case CTL_DEBUG_NAME:
384 		return (sysctl_rdstring(oldp, oldlenp, newp, cdp->debugname));
385 	case CTL_DEBUG_VALUE:
386 		return (sysctl_int(oldp, oldlenp, newp, newlen, cdp->debugvar));
387 	default:
388 		return (EOPNOTSUPP);
389 	}
390 	/* NOTREACHED */
391 }
392 #endif /* DEBUG */
393 
394 /*
395  * Validate parameters and get old / set new parameters
396  * for an integer-valued sysctl function.
397  */
398 int
399 sysctl_int(oldp, oldlenp, newp, newlen, valp)
400 	void *oldp;
401 	size_t *oldlenp;
402 	void *newp;
403 	size_t newlen;
404 	int *valp;
405 {
406 	int error = 0;
407 
408 	if (oldp && *oldlenp < sizeof(int))
409 		return (ENOMEM);
410 	if (newp && newlen != sizeof(int))
411 		return (EINVAL);
412 	*oldlenp = sizeof(int);
413 	if (oldp)
414 		error = copyout(valp, oldp, sizeof(int));
415 	if (error == 0 && newp)
416 		error = copyin(newp, valp, sizeof(int));
417 	return (error);
418 }
419 
420 /*
421  * As above, but read-only.
422  */
423 int
424 sysctl_rdint(oldp, oldlenp, newp, val)
425 	void *oldp;
426 	size_t *oldlenp;
427 	void *newp;
428 	int val;
429 {
430 	int error = 0;
431 
432 	if (oldp && *oldlenp < sizeof(int))
433 		return (ENOMEM);
434 	if (newp)
435 		return (EPERM);
436 	*oldlenp = sizeof(int);
437 	if (oldp)
438 		error = copyout((caddr_t)&val, oldp, sizeof(int));
439 	return (error);
440 }
441 
442 /*
443  * Validate parameters and get old / set new parameters
444  * for a string-valued sysctl function.
445  */
446 int
447 sysctl_string(oldp, oldlenp, newp, newlen, str, maxlen)
448 	void *oldp;
449 	size_t *oldlenp;
450 	void *newp;
451 	size_t newlen;
452 	char *str;
453 	int maxlen;
454 {
455 	int len, error = 0;
456 
457 	len = strlen(str) + 1;
458 	if (oldp && *oldlenp < len)
459 		len = *oldlenp;
460 	if (newp && newlen >= maxlen)
461 		return (EINVAL);
462 	if (oldp) {
463 		*oldlenp = len;
464 		error = copyout(str, oldp, len);
465 	}
466 	if (error == 0 && newp) {
467 		error = copyin(newp, str, newlen);
468 		str[newlen] = 0;
469 	}
470 	return (error);
471 }
472 
473 /*
474  * As above, but read-only.
475  */
476 int
477 sysctl_rdstring(oldp, oldlenp, newp, str)
478 	void *oldp;
479 	size_t *oldlenp;
480 	void *newp;
481 	char *str;
482 {
483 	int len, error = 0;
484 
485 	len = strlen(str) + 1;
486 	if (oldp && *oldlenp < len)
487 		return (ENOMEM);
488 	if (newp)
489 		return (EPERM);
490 	*oldlenp = len;
491 	if (oldp)
492 		error = copyout(str, oldp, len);
493 	return (error);
494 }
495 
496 /*
497  * Validate parameters and get old / set new parameters
498  * for a structure oriented sysctl function.
499  */
500 int
501 sysctl_struct(oldp, oldlenp, newp, newlen, sp, len)
502 	void *oldp;
503 	size_t *oldlenp;
504 	void *newp;
505 	size_t newlen;
506 	void *sp;
507 	int len;
508 {
509 	int error = 0;
510 
511 	if (oldp && *oldlenp < len)
512 		return (ENOMEM);
513 	if (newp && newlen > len)
514 		return (EINVAL);
515 	if (oldp) {
516 		*oldlenp = len;
517 		error = copyout(sp, oldp, len);
518 	}
519 	if (error == 0 && newp)
520 		error = copyin(newp, sp, len);
521 	return (error);
522 }
523 
524 /*
525  * Validate parameters and get old parameters
526  * for a structure oriented sysctl function.
527  */
528 int
529 sysctl_rdstruct(oldp, oldlenp, newp, sp, len)
530 	void *oldp;
531 	size_t *oldlenp;
532 	void *newp, *sp;
533 	int len;
534 {
535 	int error = 0;
536 
537 	if (oldp && *oldlenp < len)
538 		return (ENOMEM);
539 	if (newp)
540 		return (EPERM);
541 	*oldlenp = len;
542 	if (oldp)
543 		error = copyout(sp, oldp, len);
544 	return (error);
545 }
546 
547 /*
548  * Get file structures.
549  */
550 int
551 sysctl_file(where, sizep)
552 	char *where;
553 	size_t *sizep;
554 {
555 	int buflen, error;
556 	struct file *fp;
557 	char *start = where;
558 
559 	buflen = *sizep;
560 	if (where == NULL) {
561 		/*
562 		 * overestimate by 10 files
563 		 */
564 		*sizep = sizeof(filehead) + (nfiles + 10) * sizeof(struct file);
565 		return (0);
566 	}
567 
568 	/*
569 	 * first copyout filehead
570 	 */
571 	if (buflen < sizeof(filehead)) {
572 		*sizep = 0;
573 		return (0);
574 	}
575 	error = copyout((caddr_t)&filehead, where, sizeof(filehead));
576 	if (error)
577 		return (error);
578 	buflen -= sizeof(filehead);
579 	where += sizeof(filehead);
580 
581 	/*
582 	 * followed by an array of file structures
583 	 */
584 	for (fp = filehead; fp != NULL; fp = fp->f_filef) {
585 		if (buflen < sizeof(struct file)) {
586 			*sizep = where - start;
587 			return (ENOMEM);
588 		}
589 		error = copyout((caddr_t)fp, where, sizeof (struct file));
590 		if (error)
591 			return (error);
592 		buflen -= sizeof(struct file);
593 		where += sizeof(struct file);
594 	}
595 	*sizep = where - start;
596 	return (0);
597 }
598 
599 /*
600  * try over estimating by 5 procs
601  */
602 #define KERN_PROCSLOP	(5 * sizeof (struct kinfo_proc))
603 
604 int
605 sysctl_doproc(name, namelen, where, sizep)
606 	int *name;
607 	u_int namelen;
608 	char *where;
609 	size_t *sizep;
610 {
611 	register struct proc *p;
612 	register struct kinfo_proc *dp = (struct kinfo_proc *)where;
613 	register int needed = 0;
614 	int buflen = where != NULL ? *sizep : 0;
615 	int doingzomb;
616 	struct eproc eproc;
617 	int error = 0;
618 
619 	if (namelen != 2 && !(namelen == 1 && name[0] == KERN_PROC_ALL))
620 		return (EINVAL);
621 	p = (struct proc *)allproc;
622 	doingzomb = 0;
623 again:
624 	for (; p != NULL; p = p->p_next) {
625 		/*
626 		 * Skip embryonic processes.
627 		 */
628 		if (p->p_stat == SIDL)
629 			continue;
630 		/*
631 		 * TODO - make more efficient (see notes below).
632 		 * do by session.
633 		 */
634 		switch (name[0]) {
635 
636 		case KERN_PROC_PID:
637 			/* could do this with just a lookup */
638 			if (p->p_pid != (pid_t)name[1])
639 				continue;
640 			break;
641 
642 		case KERN_PROC_PGRP:
643 			/* could do this by traversing pgrp */
644 			if (p->p_pgrp == NULL || p->p_pgrp->pg_id != (pid_t)name[1])
645 				continue;
646 			break;
647 
648 		case KERN_PROC_TTY:
649 			if ((p->p_flag & P_CONTROLT) == 0 ||
650 			    p->p_session == NULL ||
651 			    p->p_session->s_ttyp == NULL ||
652 			    p->p_session->s_ttyp->t_dev != (dev_t)name[1])
653 				continue;
654 			break;
655 
656 		case KERN_PROC_UID:
657 			if (p->p_ucred == NULL || p->p_ucred->cr_uid != (uid_t)name[1])
658 				continue;
659 			break;
660 
661 		case KERN_PROC_RUID:
662 			if (p->p_ucred == NULL || p->p_cred->p_ruid != (uid_t)name[1])
663 				continue;
664 			break;
665 		}
666 		if (buflen >= sizeof(struct kinfo_proc)) {
667 			fill_eproc(p, &eproc);
668 			error = copyout((caddr_t)p, &dp->kp_proc,
669 			    sizeof(struct proc));
670 			if (error)
671 				return (error);
672 			error = copyout((caddr_t)&eproc, &dp->kp_eproc,
673 			    sizeof(eproc));
674 			if (error)
675 				return (error);
676 			dp++;
677 			buflen -= sizeof(struct kinfo_proc);
678 		}
679 		needed += sizeof(struct kinfo_proc);
680 	}
681 	if (doingzomb == 0) {
682 		p = zombproc;
683 		doingzomb++;
684 		goto again;
685 	}
686 	if (where != NULL) {
687 		*sizep = (caddr_t)dp - where;
688 		if (needed > *sizep)
689 			return (ENOMEM);
690 	} else {
691 		needed += KERN_PROCSLOP;
692 		*sizep = needed;
693 	}
694 	return (0);
695 }
696 
697 /*
698  * Fill in an eproc structure for the specified process.
699  */
700 void
701 fill_eproc(p, ep)
702 	register struct proc *p;
703 	register struct eproc *ep;
704 {
705 	register struct tty *tp;
706 
707 	bzero(ep, sizeof(*ep));
708 
709 	ep->e_paddr = p;
710 	if (p->p_cred)
711 		ep->e_pcred = *p->p_cred;
712 	if (p->p_ucred)
713 		ep->e_ucred = *p->p_ucred;
714 	if (p->p_stat != SIDL && p->p_stat != SZOMB) {
715 		register struct vmspace *vm = p->p_vmspace;
716 
717 #ifdef pmap_resident_count
718 		ep->e_vm.vm_rssize = pmap_resident_count(&vm->vm_pmap); /*XXX*/
719 #else
720 		ep->e_vm.vm_rssize = vm->vm_rssize;
721 #endif
722 		ep->e_vm.vm_tsize = vm->vm_tsize;
723 		ep->e_vm.vm_dsize = vm->vm_dsize;
724 		ep->e_vm.vm_ssize = vm->vm_ssize;
725 #ifndef sparc
726 		ep->e_vm.vm_pmap = vm->vm_pmap;
727 #endif
728 	}
729 	if (p->p_pptr)
730 		ep->e_ppid = p->p_pptr->p_pid;
731 	if (p->p_pgrp) {
732 		ep->e_sess = p->p_pgrp->pg_session;
733 		ep->e_pgid = p->p_pgrp->pg_id;
734 		ep->e_jobc = p->p_pgrp->pg_jobc;
735 	}
736 	if ((p->p_flag & P_CONTROLT) &&
737 	    (ep->e_sess != NULL) &&
738 	    ((tp = ep->e_sess->s_ttyp) != NULL)) {
739 		ep->e_tdev = tp->t_dev;
740 		ep->e_tpgid = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID;
741 		ep->e_tsess = tp->t_session;
742 	} else
743 		ep->e_tdev = NODEV;
744 	if (ep->e_sess && ep->e_sess->s_ttyvp)
745 		ep->e_flag = EPROC_CTTY;
746 	if (SESS_LEADER(p))
747 		ep->e_flag |= EPROC_SLEADER;
748 	if (p->p_wmesg) {
749 		strncpy(ep->e_wmesg, p->p_wmesg, WMESGLEN);
750 		ep->e_wmesg[WMESGLEN] = 0;
751 	}
752 }
753 
754 #ifdef COMPAT_43
755 #include <sys/socket.h>
756 #define	KINFO_PROC		(0<<8)
757 #define	KINFO_RT		(1<<8)
758 #define	KINFO_VNODE		(2<<8)
759 #define	KINFO_FILE		(3<<8)
760 #define	KINFO_METER		(4<<8)
761 #define	KINFO_LOADAVG		(5<<8)
762 #define	KINFO_CLOCKRATE		(6<<8)
763 
764 struct getkerninfo_args {
765 	int	op;
766 	char	*where;
767 	int	*size;
768 	int	arg;
769 };
770 
771 int
772 ogetkerninfo(p, uap, retval)
773 	struct proc *p;
774 	register struct getkerninfo_args *uap;
775 	int *retval;
776 {
777 	int error, name[5];
778 	u_int size;
779 
780 	if (uap->size &&
781 	    (error = copyin((caddr_t)uap->size, (caddr_t)&size, sizeof(size))))
782 		return (error);
783 
784 	switch (uap->op & 0xff00) {
785 
786 	case KINFO_RT:
787 		name[0] = PF_ROUTE;
788 		name[1] = 0;
789 		name[2] = (uap->op & 0xff0000) >> 16;
790 		name[3] = uap->op & 0xff;
791 		name[4] = uap->arg;
792 		error = net_sysctl(name, 5, uap->where, &size, NULL, 0, p);
793 		break;
794 
795 	case KINFO_VNODE:
796 		name[0] = KERN_VNODE;
797 		error = kern_sysctl(name, 1, uap->where, &size, NULL, 0, p);
798 		break;
799 
800 	case KINFO_PROC:
801 		name[0] = KERN_PROC;
802 		name[1] = uap->op & 0xff;
803 		name[2] = uap->arg;
804 		error = kern_sysctl(name, 3, uap->where, &size, NULL, 0, p);
805 		break;
806 
807 	case KINFO_FILE:
808 		name[0] = KERN_FILE;
809 		error = kern_sysctl(name, 1, uap->where, &size, NULL, 0, p);
810 		break;
811 
812 	case KINFO_METER:
813 		name[0] = VM_METER;
814 		error = vm_sysctl(name, 1, uap->where, &size, NULL, 0, p);
815 		break;
816 
817 	case KINFO_LOADAVG:
818 		name[0] = VM_LOADAVG;
819 		error = vm_sysctl(name, 1, uap->where, &size, NULL, 0, p);
820 		break;
821 
822 	case KINFO_CLOCKRATE:
823 		name[0] = KERN_CLOCKRATE;
824 		error = kern_sysctl(name, 1, uap->where, &size, NULL, 0, p);
825 		break;
826 
827 	default:
828 		return (EOPNOTSUPP);
829 	}
830 	if (error)
831 		return (error);
832 	*retval = size;
833 	if (uap->size)
834 		error = copyout((caddr_t)&size, (caddr_t)uap->size,
835 		    sizeof(size));
836 	return (error);
837 }
838 #endif /* COMPAT_43 */
839