kern_sysctl.c revision 9816
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
60static sysctlfn debug_sysctl;
61#endif
62
63/*
64 * Locking and stats
65 */
66static struct sysctl_lock {
67	int	sl_lock;
68	int	sl_want;
69	int	sl_locked;
70} memlock;
71
72struct 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
81int
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 */
171char hostname[MAXHOSTNAMELEN];
172int hostnamelen;
173char domainname[MAXHOSTNAMELEN];
174int domainnamelen;
175long hostid;
176int securelevel = -1;
177char kernelname[MAXPATHLEN] = "/kernel";	/* XXX bloat */
178extern int vfs_update_wakeup;
179extern int vfs_update_interval;
180extern int osreldate;
181
182/*
183 * kernel related system variables.
184 */
185int
186kern_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 */
317int
318hw_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 */
362struct ctldebug debug0, debug1, debug2, debug3, debug4;
363struct ctldebug debug5, debug6, debug7, debug8, debug9;
364struct ctldebug debug10, debug11, debug12, debug13, debug14;
365struct ctldebug debug15, debug16, debug17, debug18, debug19;
366static 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};
372static int
373debug_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 */
406int
407sysctl_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 */
431int
432sysctl_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 */
454int
455sysctl_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 */
490int
491sysctl_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 */
518int
519sysctl_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 */
546int
547sysctl_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 */
568int
569sysctl_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
622int
623sysctl_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;
641again:
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 */
718void
719fill_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
791struct {
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 */
828char bsdi_strings[80];	/* It had better be less than this! */
829
830struct getkerninfo_args {
831	int	op;
832	char	*where;
833	int	*size;
834	int	arg;
835};
836
837int
838ogetkerninfo(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