xref: /freebsd/sys/kern/kern_sysctl.c (revision 8e6b01171e30297084bb0b4457c4183c2746aacc)
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.27 1995/07/28 18:04:47 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 <sys/conf.h>
56 #include <vm/vm.h>
57 #include <sys/sysctl.h>
58 
59 #ifdef DEBUG
60 static sysctlfn debug_sysctl;
61 #endif
62 
63 /*
64  * Locking and stats
65  */
66 static struct sysctl_lock {
67 	int	sl_lock;
68 	int	sl_want;
69 	int	sl_locked;
70 } memlock;
71 
72 struct sysctl_args {
73 	int	*name;
74 	u_int	namelen;
75 	void	*old;
76 	size_t	*oldlenp;
77 	void	*new;
78 	size_t	newlen;
79 };
80 
81 int
82 __sysctl(p, uap, retval)
83 	struct proc *p;
84 	register struct sysctl_args *uap;
85 	int *retval;
86 {
87 	int error, dolock = 1;
88 	u_int savelen = 0, oldlen = 0;
89 	sysctlfn *fn;
90 	int name[CTL_MAXNAME];
91 
92 	if (uap->new != NULL && (error = suser(p->p_ucred, &p->p_acflag)))
93 		return (error);
94 	/*
95 	 * all top-level sysctl names are non-terminal
96 	 */
97 	if (uap->namelen > CTL_MAXNAME || uap->namelen < 2)
98 		return (EINVAL);
99  	error = copyin(uap->name, &name, uap->namelen * sizeof(int));
100  	if (error)
101 		return (error);
102 
103 	switch (name[0]) {
104 	case CTL_KERN:
105 		fn = kern_sysctl;
106 		if (name[1] != KERN_VNODE)      /* XXX */
107 			dolock = 0;
108 		break;
109 	case CTL_HW:
110 		fn = hw_sysctl;
111 		break;
112 	case CTL_VM:
113 		fn = vm_sysctl;
114 		break;
115 	case CTL_NET:
116 		fn = net_sysctl;
117 		break;
118 	case CTL_FS:
119 		fn = fs_sysctl;
120 		break;
121 	case CTL_MACHDEP:
122 		fn = cpu_sysctl;
123 		break;
124 #ifdef DEBUG
125 	case CTL_DEBUG:
126 		fn = debug_sysctl;
127 		break;
128 #endif
129 	default:
130 		return (EOPNOTSUPP);
131 	}
132 
133 	if (uap->oldlenp &&
134 	    (error = copyin(uap->oldlenp, &oldlen, sizeof(oldlen))))
135 		return (error);
136 	if (uap->old != NULL) {
137 		if (!useracc(uap->old, oldlen, B_WRITE))
138 			return (EFAULT);
139 		while (memlock.sl_lock) {
140 			memlock.sl_want = 1;
141 			(void) tsleep((caddr_t)&memlock, PRIBIO+1, "sysctl", 0);
142 			memlock.sl_locked++;
143 		}
144 		memlock.sl_lock = 1;
145 		if (dolock)
146 			vslock(uap->old, oldlen);
147 		savelen = oldlen;
148 	}
149 	error = (*fn)(name + 1, uap->namelen - 1, uap->old, &oldlen,
150 	    uap->new, uap->newlen, p);
151 	if (uap->old != NULL) {
152 		if (dolock)
153 			vsunlock(uap->old, savelen, B_WRITE);
154 		memlock.sl_lock = 0;
155 		if (memlock.sl_want) {
156 			memlock.sl_want = 0;
157 			wakeup((caddr_t)&memlock);
158 		}
159 	}
160 	if (error)
161 		return (error);
162 	if (uap->oldlenp)
163 		error = copyout(&oldlen, uap->oldlenp, sizeof(oldlen));
164 	*retval = oldlen;
165 	return (0);
166 }
167 
168 /*
169  * Attributes stored in the kernel.
170  */
171 char hostname[MAXHOSTNAMELEN];
172 int hostnamelen;
173 char domainname[MAXHOSTNAMELEN];
174 int domainnamelen;
175 long hostid;
176 int securelevel = -1;
177 char kernelname[MAXPATHLEN] = "/kernel";	/* XXX bloat */
178 extern int vfs_update_wakeup;
179 extern int vfs_update_interval;
180 extern int osreldate;
181 
182 /*
183  * kernel related system variables.
184  */
185 int
186 kern_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
187 	int *name;
188 	u_int namelen;
189 	void *oldp;
190 	size_t *oldlenp;
191 	void *newp;
192 	size_t newlen;
193 	struct proc *p;
194 {
195 	int error, level, inthostid;
196 	dev_t ndumpdev;
197 
198 	/* all sysctl names at this level are terminal */
199 	if (namelen != 1 && !(name[0] == KERN_PROC || name[0] == KERN_PROF
200 			      || name[0] == KERN_NTP_PLL))
201 		return (ENOTDIR);		/* overloaded */
202 
203 	switch (name[0]) {
204 	case KERN_OSTYPE:
205 		return (sysctl_rdstring(oldp, oldlenp, newp, ostype));
206 	case KERN_OSRELEASE:
207 		return (sysctl_rdstring(oldp, oldlenp, newp, osrelease));
208 	case KERN_OSREV:
209 		return (sysctl_rdint(oldp, oldlenp, newp, BSD));
210 	case KERN_VERSION:
211 		return (sysctl_rdstring(oldp, oldlenp, newp, version));
212 	case KERN_OSRELDATE:
213 		return (sysctl_rdint(oldp, oldlenp, newp, osreldate));
214 	case KERN_BOOTFILE:
215 		return (sysctl_string(oldp, oldlenp, newp, newlen,
216 				      kernelname, sizeof kernelname));
217 	case KERN_MAXVNODES:
218 		return(sysctl_int(oldp, oldlenp, newp, newlen, &desiredvnodes));
219 	case KERN_MAXPROC:
220 		return (sysctl_int(oldp, oldlenp, newp, newlen, &maxproc));
221 	case KERN_MAXPROCPERUID:
222 		return (sysctl_int(oldp, oldlenp, newp, newlen, &maxprocperuid));
223 	case KERN_MAXFILES:
224 		return (sysctl_int(oldp, oldlenp, newp, newlen, &maxfiles));
225 	case KERN_MAXFILESPERPROC:
226 		return (sysctl_int(oldp, oldlenp, newp, newlen, &maxfilesperproc));
227 	case KERN_UPDATEINTERVAL:
228 		/*
229 		 * NB: this simple-minded approach only works because
230 		 * `tsleep' takes a timeout argument of 0 as meaning
231 		 * `no timeout'.
232 		 */
233 		error = sysctl_int(oldp, oldlenp, newp, newlen,
234 				   &vfs_update_interval);
235 		if(!error) {
236 			wakeup(&vfs_update_wakeup);
237 		}
238 		return error;
239 	case KERN_ARGMAX:
240 		return (sysctl_rdint(oldp, oldlenp, newp, ARG_MAX));
241 	case KERN_SECURELVL:
242 		level = securelevel;
243 		if ((error = sysctl_int(oldp, oldlenp, newp, newlen, &level)) ||
244 		    newp == NULL)
245 			return (error);
246 		if (level < securelevel && p->p_pid != 1)
247 			return (EPERM);
248 		securelevel = level;
249 		return (0);
250 	case KERN_HOSTNAME:
251 		error = sysctl_string(oldp, oldlenp, newp, newlen,
252 		    hostname, sizeof(hostname));
253 		if (newp)
254 			if (error == 0 || error == ENOMEM)
255 				hostnamelen = newlen;
256 		return (error);
257 	case KERN_DOMAINNAME:
258 		error = sysctl_string(oldp, oldlenp, newp, newlen,
259 		    domainname, sizeof(domainname));
260 		if (newp)
261 			if (error == 0 || error == ENOMEM)
262 				domainnamelen = newlen;
263 		return (error);
264 	case KERN_HOSTID:
265 		inthostid = hostid;  /* XXX assumes sizeof long <= sizeof int */
266 		error =  sysctl_int(oldp, oldlenp, newp, newlen, &inthostid);
267 		hostid = inthostid;
268 		return (error);
269 	case KERN_CLOCKRATE:
270 		return (sysctl_clockrate(oldp, oldlenp));
271 	case KERN_BOOTTIME:
272 		return (sysctl_rdstruct(oldp, oldlenp, newp, &boottime,
273 		    sizeof(struct timeval)));
274 	case KERN_VNODE:
275 		return (sysctl_vnode(oldp, oldlenp));
276 	case KERN_PROC:
277 		return (sysctl_doproc(name + 1, namelen - 1, oldp, oldlenp));
278 	case KERN_FILE:
279 		return (sysctl_file(oldp, oldlenp));
280 #ifdef GPROF
281 	case KERN_PROF:
282 		return (sysctl_doprof(name + 1, namelen - 1, oldp, oldlenp,
283 		    newp, newlen));
284 #endif
285 	case KERN_POSIX1:
286 		return (sysctl_rdint(oldp, oldlenp, newp, _POSIX_VERSION));
287 	case KERN_NGROUPS:
288 		return (sysctl_rdint(oldp, oldlenp, newp, NGROUPS_MAX));
289 	case KERN_JOB_CONTROL:
290 		return (sysctl_rdint(oldp, oldlenp, newp, 1));
291 	case KERN_SAVED_IDS:
292 #ifdef _POSIX_SAVED_IDS
293 		return (sysctl_rdint(oldp, oldlenp, newp, 1));
294 #else
295 		return (sysctl_rdint(oldp, oldlenp, newp, 0));
296 #endif
297 	case KERN_NTP_PLL:
298 		return (ntp_sysctl(name + 1, namelen - 1, oldp, oldlenp,
299 				   newp, newlen, p));
300 	case KERN_DUMPDEV:
301 		ndumpdev = dumpdev;
302 		error = sysctl_struct(oldp, oldlenp, newp, newlen, &ndumpdev,
303 				      sizeof ndumpdev);
304 		if (!error && ndumpdev != dumpdev) {
305 			error = setdumpdev(ndumpdev);
306 		}
307 		return error;
308 	default:
309 		return (EOPNOTSUPP);
310 	}
311 	/* NOTREACHED */
312 }
313 
314 /*
315  * hardware related system variables.
316  */
317 int
318 hw_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
319 	int *name;
320 	u_int namelen;
321 	void *oldp;
322 	size_t *oldlenp;
323 	void *newp;
324 	size_t newlen;
325 	struct proc *p;
326 {
327 	/* almost all sysctl names at this level are terminal */
328 	if (namelen != 1 && name[0] != HW_DEVCONF)
329 		return (ENOTDIR);		/* overloaded */
330 
331 	switch (name[0]) {
332 	case HW_MACHINE:
333 		return (sysctl_rdstring(oldp, oldlenp, newp, machine));
334 	case HW_MODEL:
335 		return (sysctl_rdstring(oldp, oldlenp, newp, cpu_model));
336 	case HW_NCPU:
337 		return (sysctl_rdint(oldp, oldlenp, newp, 1));	/* XXX */
338 	case HW_BYTEORDER:
339 		return (sysctl_rdint(oldp, oldlenp, newp, BYTE_ORDER));
340 	case HW_PHYSMEM:
341 		return (sysctl_rdint(oldp, oldlenp, newp, ctob(physmem)));
342 	case HW_USERMEM:
343 		return (sysctl_rdint(oldp, oldlenp, newp,
344 		    ctob(physmem - cnt.v_wire_count)));
345 	case HW_PAGESIZE:
346 		return (sysctl_rdint(oldp, oldlenp, newp, PAGE_SIZE));
347 	case HW_FLOATINGPT:
348 		return (sysctl_rdint(oldp, oldlenp, newp, hw_float));
349 	case HW_DEVCONF:
350 		return (dev_sysctl(name + 1, namelen - 1, oldp, oldlenp,
351 				   newp, newlen, p));
352 	default:
353 		return (EOPNOTSUPP);
354 	}
355 	/* NOTREACHED */
356 }
357 
358 #ifdef DEBUG
359 /*
360  * Debugging related system variables.
361  */
362 struct ctldebug debug0, debug1, debug2, debug3, debug4;
363 struct ctldebug debug5, debug6, debug7, debug8, debug9;
364 struct ctldebug debug10, debug11, debug12, debug13, debug14;
365 struct ctldebug debug15, debug16, debug17, debug18, debug19;
366 static struct ctldebug *debugvars[CTL_DEBUG_MAXID] = {
367 	&debug0, &debug1, &debug2, &debug3, &debug4,
368 	&debug5, &debug6, &debug7, &debug8, &debug9,
369 	&debug10, &debug11, &debug12, &debug13, &debug14,
370 	&debug15, &debug16, &debug17, &debug18, &debug19,
371 };
372 static int
373 debug_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
374 	int *name;
375 	u_int namelen;
376 	void *oldp;
377 	size_t *oldlenp;
378 	void *newp;
379 	size_t newlen;
380 	struct proc *p;
381 {
382 	struct ctldebug *cdp;
383 
384 	/* all sysctl names at this level are name and field */
385 	if (namelen != 2)
386 		return (ENOTDIR);		/* overloaded */
387 	cdp = debugvars[name[0]];
388 	if (cdp->debugname == 0)
389 		return (EOPNOTSUPP);
390 	switch (name[1]) {
391 	case CTL_DEBUG_NAME:
392 		return (sysctl_rdstring(oldp, oldlenp, newp, cdp->debugname));
393 	case CTL_DEBUG_VALUE:
394 		return (sysctl_int(oldp, oldlenp, newp, newlen, cdp->debugvar));
395 	default:
396 		return (EOPNOTSUPP);
397 	}
398 	/* NOTREACHED */
399 }
400 #endif /* DEBUG */
401 
402 /*
403  * Validate parameters and get old / set new parameters
404  * for an integer-valued sysctl function.
405  */
406 int
407 sysctl_int(oldp, oldlenp, newp, newlen, valp)
408 	void *oldp;
409 	size_t *oldlenp;
410 	void *newp;
411 	size_t newlen;
412 	int *valp;
413 {
414 	int error = 0;
415 
416 	if (oldp && *oldlenp < sizeof(int))
417 		return (ENOMEM);
418 	if (newp && newlen != sizeof(int))
419 		return (EINVAL);
420 	*oldlenp = sizeof(int);
421 	if (oldp)
422 		error = copyout(valp, oldp, sizeof(int));
423 	if (error == 0 && newp)
424 		error = copyin(newp, valp, sizeof(int));
425 	return (error);
426 }
427 
428 /*
429  * As above, but read-only.
430  */
431 int
432 sysctl_rdint(oldp, oldlenp, newp, val)
433 	void *oldp;
434 	size_t *oldlenp;
435 	void *newp;
436 	int val;
437 {
438 	int error = 0;
439 
440 	if (oldp && *oldlenp < sizeof(int))
441 		return (ENOMEM);
442 	if (newp)
443 		return (EPERM);
444 	*oldlenp = sizeof(int);
445 	if (oldp)
446 		error = copyout((caddr_t)&val, oldp, sizeof(int));
447 	return (error);
448 }
449 
450 /*
451  * Validate parameters and get old / set new parameters
452  * for a string-valued sysctl function.
453  */
454 int
455 sysctl_string(oldp, oldlenp, newp, newlen, str, maxlen)
456 	void *oldp;
457 	size_t *oldlenp;
458 	void *newp;
459 	size_t newlen;
460 	char *str;
461 	int maxlen;
462 {
463 	int len, error = 0, rval = 0;
464 
465 	len = strlen(str) + 1;
466 	if (oldp && *oldlenp < len) {
467 		len = *oldlenp;
468 		rval = ENOMEM;
469 	}
470 	if (newp && newlen >= maxlen)
471 		return (EINVAL);
472 	if (oldp) {
473 		*oldlenp = len;
474 		error = copyout(str, oldp, len);
475 		if (error)
476 			rval = error;
477 	}
478 	if ((error == 0 || error == ENOMEM) && newp) {
479 		error = copyin(newp, str, newlen);
480 		if (error)
481 			rval = error;
482 		str[newlen] = 0;
483 	}
484 	return (rval);
485 }
486 
487 /*
488  * As above, but read-only.
489  */
490 int
491 sysctl_rdstring(oldp, oldlenp, newp, str)
492 	void *oldp;
493 	size_t *oldlenp;
494 	void *newp;
495 	char *str;
496 {
497 	int len, error = 0, rval = 0;
498 
499 	len = strlen(str) + 1;
500 	if (oldp && *oldlenp < len) {
501 		len = *oldlenp;
502 		rval = ENOMEM;
503 	}
504 	if (newp)
505 		return (EPERM);
506 	*oldlenp = len;
507 	if (oldp)
508 		error = copyout(str, oldp, len);
509 		if (error)
510 			rval = error;
511 	return (rval);
512 }
513 
514 /*
515  * Validate parameters and get old / set new parameters
516  * for a structure oriented sysctl function.
517  */
518 int
519 sysctl_struct(oldp, oldlenp, newp, newlen, sp, len)
520 	void *oldp;
521 	size_t *oldlenp;
522 	void *newp;
523 	size_t newlen;
524 	void *sp;
525 	int len;
526 {
527 	int error = 0;
528 
529 	if (oldp && *oldlenp < len)
530 		return (ENOMEM);
531 	if (newp && newlen > len)
532 		return (EINVAL);
533 	if (oldp) {
534 		*oldlenp = len;
535 		error = copyout(sp, oldp, len);
536 	}
537 	if (error == 0 && newp)
538 		error = copyin(newp, sp, len);
539 	return (error);
540 }
541 
542 /*
543  * Validate parameters and get old parameters
544  * for a structure oriented sysctl function.
545  */
546 int
547 sysctl_rdstruct(oldp, oldlenp, newp, sp, len)
548 	void *oldp;
549 	size_t *oldlenp;
550 	void *newp, *sp;
551 	int len;
552 {
553 	int error = 0;
554 
555 	if (oldp && *oldlenp < len)
556 		return (ENOMEM);
557 	if (newp)
558 		return (EPERM);
559 	*oldlenp = len;
560 	if (oldp)
561 		error = copyout(sp, oldp, len);
562 	return (error);
563 }
564 
565 /*
566  * Get file structures.
567  */
568 int
569 sysctl_file(where, sizep)
570 	char *where;
571 	size_t *sizep;
572 {
573 	int buflen, error;
574 	struct file *fp;
575 	char *start = where;
576 
577 	buflen = *sizep;
578 	if (where == NULL) {
579 		/*
580 		 * overestimate by 10 files
581 		 */
582 		*sizep = sizeof(filehead) + (nfiles + 10) * sizeof(struct file);
583 		return (0);
584 	}
585 
586 	/*
587 	 * first copyout filehead
588 	 */
589 	if (buflen < sizeof(filehead)) {
590 		*sizep = 0;
591 		return (0);
592 	}
593 	error = copyout((caddr_t)&filehead, where, sizeof(filehead));
594 	if (error)
595 		return (error);
596 	buflen -= sizeof(filehead);
597 	where += sizeof(filehead);
598 
599 	/*
600 	 * followed by an array of file structures
601 	 */
602 	for (fp = filehead; fp != NULL; fp = fp->f_filef) {
603 		if (buflen < sizeof(struct file)) {
604 			*sizep = where - start;
605 			return (ENOMEM);
606 		}
607 		error = copyout((caddr_t)fp, where, sizeof (struct file));
608 		if (error)
609 			return (error);
610 		buflen -= sizeof(struct file);
611 		where += sizeof(struct file);
612 	}
613 	*sizep = where - start;
614 	return (0);
615 }
616 
617 /*
618  * try over estimating by 5 procs
619  */
620 #define KERN_PROCSLOP	(5 * sizeof (struct kinfo_proc))
621 
622 int
623 sysctl_doproc(name, namelen, where, sizep)
624 	int *name;
625 	u_int namelen;
626 	char *where;
627 	size_t *sizep;
628 {
629 	register struct proc *p;
630 	register struct kinfo_proc *dp = (struct kinfo_proc *)where;
631 	register int needed = 0;
632 	int buflen = where != NULL ? *sizep : 0;
633 	int doingzomb;
634 	struct eproc eproc;
635 	int error = 0;
636 
637 	if (namelen != 2 && !(namelen == 1 && name[0] == KERN_PROC_ALL))
638 		return (EINVAL);
639 	p = (struct proc *)allproc;
640 	doingzomb = 0;
641 again:
642 	for (; p != NULL; p = p->p_next) {
643 		/*
644 		 * Skip embryonic processes.
645 		 */
646 		if (p->p_stat == SIDL)
647 			continue;
648 		/*
649 		 * TODO - make more efficient (see notes below).
650 		 * do by session.
651 		 */
652 		switch (name[0]) {
653 
654 		case KERN_PROC_PID:
655 			/* could do this with just a lookup */
656 			if (p->p_pid != (pid_t)name[1])
657 				continue;
658 			break;
659 
660 		case KERN_PROC_PGRP:
661 			/* could do this by traversing pgrp */
662 			if (p->p_pgrp == NULL || p->p_pgrp->pg_id != (pid_t)name[1])
663 				continue;
664 			break;
665 
666 		case KERN_PROC_TTY:
667 			if ((p->p_flag & P_CONTROLT) == 0 ||
668 			    p->p_session == NULL ||
669 			    p->p_session->s_ttyp == NULL ||
670 			    p->p_session->s_ttyp->t_dev != (dev_t)name[1])
671 				continue;
672 			break;
673 
674 		case KERN_PROC_UID:
675 			if (p->p_ucred == NULL || p->p_ucred->cr_uid != (uid_t)name[1])
676 				continue;
677 			break;
678 
679 		case KERN_PROC_RUID:
680 			if (p->p_ucred == NULL || p->p_cred->p_ruid != (uid_t)name[1])
681 				continue;
682 			break;
683 		}
684 		if (buflen >= sizeof(struct kinfo_proc)) {
685 			fill_eproc(p, &eproc);
686 			error = copyout((caddr_t)p, &dp->kp_proc,
687 			    sizeof(struct proc));
688 			if (error)
689 				return (error);
690 			error = copyout((caddr_t)&eproc, &dp->kp_eproc,
691 			    sizeof(eproc));
692 			if (error)
693 				return (error);
694 			dp++;
695 			buflen -= sizeof(struct kinfo_proc);
696 		}
697 		needed += sizeof(struct kinfo_proc);
698 	}
699 	if (doingzomb == 0) {
700 		p = zombproc;
701 		doingzomb++;
702 		goto again;
703 	}
704 	if (where != NULL) {
705 		*sizep = (caddr_t)dp - where;
706 		if (needed > *sizep)
707 			return (ENOMEM);
708 	} else {
709 		needed += KERN_PROCSLOP;
710 		*sizep = needed;
711 	}
712 	return (0);
713 }
714 
715 /*
716  * Fill in an eproc structure for the specified process.
717  */
718 void
719 fill_eproc(p, ep)
720 	register struct proc *p;
721 	register struct eproc *ep;
722 {
723 	register struct tty *tp;
724 
725 	bzero(ep, sizeof(*ep));
726 
727 	ep->e_paddr = p;
728 	if (p->p_cred) {
729 		ep->e_pcred = *p->p_cred;
730 		if (p->p_ucred)
731 			ep->e_ucred = *p->p_ucred;
732 	}
733 	if (p->p_stat != SIDL && p->p_stat != SZOMB && p->p_vmspace != NULL) {
734 		register struct vmspace *vm = p->p_vmspace;
735 
736 #ifdef pmap_resident_count
737 		ep->e_vm.vm_rssize = pmap_resident_count(&vm->vm_pmap); /*XXX*/
738 #else
739 		ep->e_vm.vm_rssize = vm->vm_rssize;
740 #endif
741 		ep->e_vm.vm_tsize = vm->vm_tsize;
742 		ep->e_vm.vm_dsize = vm->vm_dsize;
743 		ep->e_vm.vm_ssize = vm->vm_ssize;
744 #ifndef sparc
745 		ep->e_vm.vm_pmap = vm->vm_pmap;
746 #endif
747 	}
748 	if (p->p_pptr)
749 		ep->e_ppid = p->p_pptr->p_pid;
750 	if (p->p_pgrp) {
751 		ep->e_sess = p->p_pgrp->pg_session;
752 		ep->e_pgid = p->p_pgrp->pg_id;
753 		ep->e_jobc = p->p_pgrp->pg_jobc;
754 	}
755 	if ((p->p_flag & P_CONTROLT) &&
756 	    (ep->e_sess != NULL) &&
757 	    ((tp = ep->e_sess->s_ttyp) != NULL)) {
758 		ep->e_tdev = tp->t_dev;
759 		ep->e_tpgid = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID;
760 		ep->e_tsess = tp->t_session;
761 	} else
762 		ep->e_tdev = NODEV;
763 	if (ep->e_sess && ep->e_sess->s_ttyvp)
764 		ep->e_flag = EPROC_CTTY;
765 	if (SESS_LEADER(p))
766 		ep->e_flag |= EPROC_SLEADER;
767 	if (p->p_wmesg) {
768 		strncpy(ep->e_wmesg, p->p_wmesg, WMESGLEN);
769 		ep->e_wmesg[WMESGLEN] = 0;
770 	}
771 }
772 
773 #ifdef COMPAT_43
774 #include <sys/socket.h>
775 #define	KINFO_PROC		(0<<8)
776 #define	KINFO_RT		(1<<8)
777 #define	KINFO_VNODE		(2<<8)
778 #define	KINFO_FILE		(3<<8)
779 #define	KINFO_METER		(4<<8)
780 #define	KINFO_LOADAVG		(5<<8)
781 #define	KINFO_CLOCKRATE		(6<<8)
782 
783 /* Non-standard BSDI extension - only present on their 4.3 net-2 releases */
784 #define	KINFO_BSDI_SYSINFO	(101<<8)
785 
786 /*
787  * XXX this is bloat, but I hope it's better here than on the potentially
788  * limited kernel stack...  -Peter
789  */
790 
791 struct {
792 	int	bsdi_machine;		/* "i386" on BSD/386 */
793 /*      ^^^ this is an offset to the string, relative to the struct start */
794 	char	*pad0;
795 	long	pad1;
796 	long	pad2;
797 	long	pad3;
798 	u_long	pad4;
799 	u_long	pad5;
800 	u_long	pad6;
801 
802 	int	bsdi_ostype;		/* "BSD/386" on BSD/386 */
803 	int	bsdi_osrelease;		/* "1.1" on BSD/386 */
804 	long	pad7;
805 	long	pad8;
806 	char	*pad9;
807 
808 	long	pad10;
809 	long	pad11;
810 	int	pad12;
811 	long	pad13;
812 	quad_t	pad14;
813 	long	pad15;
814 
815 	struct	timeval pad16;
816 	/* we dont set this, because BSDI's uname used gethostname() instead */
817 	int	bsdi_hostname;		/* hostname on BSD/386 */
818 
819 	/* the actual string data is appended here */
820 
821 } bsdi_si;
822 /*
823  * this data is appended to the end of the bsdi_si structure during copyout.
824  * The "char *" offsets are relative to the base of the bsdi_si struct.
825  * This contains "FreeBSD\02.0-BUILT-nnnnnn\0i386\0", and these strings
826  * should not exceed the length of the buffer here... (or else!! :-)
827  */
828 char bsdi_strings[80];	/* It had better be less than this! */
829 
830 struct getkerninfo_args {
831 	int	op;
832 	char	*where;
833 	int	*size;
834 	int	arg;
835 };
836 
837 int
838 ogetkerninfo(p, uap, retval)
839 	struct proc *p;
840 	register struct getkerninfo_args *uap;
841 	int *retval;
842 {
843 	int error, name[5];
844 	u_int size;
845 
846 	if (uap->size &&
847 	    (error = copyin((caddr_t)uap->size, (caddr_t)&size, sizeof(size))))
848 		return (error);
849 
850 	switch (uap->op & 0xff00) {
851 
852 	case KINFO_RT:
853 		name[0] = PF_ROUTE;
854 		name[1] = 0;
855 		name[2] = (uap->op & 0xff0000) >> 16;
856 		name[3] = uap->op & 0xff;
857 		name[4] = uap->arg;
858 		error = net_sysctl(name, 5, uap->where, &size, NULL, 0, p);
859 		break;
860 
861 	case KINFO_VNODE:
862 		name[0] = KERN_VNODE;
863 		error = kern_sysctl(name, 1, uap->where, &size, NULL, 0, p);
864 		break;
865 
866 	case KINFO_PROC:
867 		name[0] = KERN_PROC;
868 		name[1] = uap->op & 0xff;
869 		name[2] = uap->arg;
870 		error = kern_sysctl(name, 3, uap->where, &size, NULL, 0, p);
871 		break;
872 
873 	case KINFO_FILE:
874 		name[0] = KERN_FILE;
875 		error = kern_sysctl(name, 1, uap->where, &size, NULL, 0, p);
876 		break;
877 
878 	case KINFO_METER:
879 		name[0] = VM_METER;
880 		error = vm_sysctl(name, 1, uap->where, &size, NULL, 0, p);
881 		break;
882 
883 	case KINFO_LOADAVG:
884 		name[0] = VM_LOADAVG;
885 		error = vm_sysctl(name, 1, uap->where, &size, NULL, 0, p);
886 		break;
887 
888 	case KINFO_CLOCKRATE:
889 		name[0] = KERN_CLOCKRATE;
890 		error = kern_sysctl(name, 1, uap->where, &size, NULL, 0, p);
891 		break;
892 
893 	case KINFO_BSDI_SYSINFO: {
894 		/*
895 		 * this is pretty crude, but it's just enough for uname()
896 		 * from BSDI's 1.x libc to work.
897 		 *
898 		 * In particular, it doesn't return the same results when
899 		 * the supplied buffer is too small.  BSDI's version apparently
900 		 * will return the amount copied, and set the *size to how
901 		 * much was needed.  The emulation framework here isn't capable
902 		 * of that, so we just set both to the amount copied.
903 		 * BSDI's 2.x product apparently fails with ENOMEM in this
904 		 * scenario.
905 		 */
906 
907 		u_int needed;
908 		u_int left;
909 		char *s;
910 
911 		bzero((char *)&bsdi_si, sizeof(bsdi_si));
912 		bzero(bsdi_strings, sizeof(bsdi_strings));
913 
914 		s = bsdi_strings;
915 
916 		bsdi_si.bsdi_ostype = (s - bsdi_strings) + sizeof(bsdi_si);
917 		strcpy(s, ostype);
918 		s += strlen(s) + 1;
919 
920 		bsdi_si.bsdi_osrelease = (s - bsdi_strings) + sizeof(bsdi_si);
921 		strcpy(s, osrelease);
922 		s += strlen(s) + 1;
923 
924 		bsdi_si.bsdi_machine = (s - bsdi_strings) + sizeof(bsdi_si);
925 		strcpy(s, machine);
926 		s += strlen(s) + 1;
927 
928 		needed = sizeof(bsdi_si) + (s - bsdi_strings);
929 
930 		if (uap->where == NULL) {
931 			/* process is asking how much buffer to supply.. */
932 			size = needed;
933 			error = 0;
934 			break;
935 		}
936 
937 
938 		/* if too much buffer supplied, trim it down */
939 		if (size > needed)
940 			size = needed;
941 
942 		/* how much of the buffer is remaining */
943 		left = size;
944 
945 		if ((error = copyout((char *)&bsdi_si, uap->where, left)) != 0)
946 			break;
947 
948 		/* is there any point in continuing? */
949 		if (left > sizeof(bsdi_si)) {
950 			left -= sizeof(bsdi_si);
951 			error = copyout(&bsdi_strings,
952 					uap->where + sizeof(bsdi_si), left);
953 		}
954 		break;
955 	}
956 
957 	default:
958 		return (EOPNOTSUPP);
959 	}
960 	if (error)
961 		return (error);
962 	*retval = size;
963 	if (uap->size)
964 		error = copyout((caddr_t)&size, (caddr_t)uap->size,
965 		    sizeof(size));
966 	return (error);
967 }
968 #endif /* COMPAT_43 */
969