kern_sysctl.c revision 1925
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.3 1994/08/02 07:42:19 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
58sysctlfn kern_sysctl;
59sysctlfn hw_sysctl;
60#ifdef DEBUG
61sysctlfn debug_sysctl;
62#endif
63extern sysctlfn vm_sysctl;
64extern sysctlfn fs_sysctl;
65extern sysctlfn net_sysctl;
66extern sysctlfn cpu_sysctl;
67
68/*
69 * Locking and stats
70 */
71static struct sysctl_lock {
72	int	sl_lock;
73	int	sl_want;
74	int	sl_locked;
75} memlock;
76
77struct sysctl_args {
78	int	*name;
79	u_int	namelen;
80	void	*old;
81	size_t	*oldlenp;
82	void	*new;
83	size_t	newlen;
84};
85
86int
87__sysctl(p, uap, retval)
88	struct proc *p;
89	register struct sysctl_args *uap;
90	int *retval;
91{
92	int error, dolock = 1;
93	u_int savelen = 0, oldlen = 0;
94	sysctlfn *fn;
95	int name[CTL_MAXNAME];
96
97	if (uap->new != NULL && (error = suser(p->p_ucred, &p->p_acflag)))
98		return (error);
99	/*
100	 * all top-level sysctl names are non-terminal
101	 */
102	if (uap->namelen > CTL_MAXNAME || uap->namelen < 2)
103		return (EINVAL);
104	if (error = copyin(uap->name, &name, uap->namelen * sizeof(int)))
105		return (error);
106
107	switch (name[0]) {
108	case CTL_KERN:
109		fn = kern_sysctl;
110		if (name[2] != KERN_VNODE)	/* XXX */
111			dolock = 0;
112		break;
113	case CTL_HW:
114		fn = hw_sysctl;
115		break;
116	case CTL_VM:
117		fn = vm_sysctl;
118		break;
119	case CTL_NET:
120		fn = net_sysctl;
121		break;
122#ifdef notyet
123	case CTL_FS:
124		fn = fs_sysctl;
125		break;
126#endif
127	case CTL_MACHDEP:
128		fn = cpu_sysctl;
129		break;
130#ifdef DEBUG
131	case CTL_DEBUG:
132		fn = debug_sysctl;
133		break;
134#endif
135	default:
136		return (EOPNOTSUPP);
137	}
138
139	if (uap->oldlenp &&
140	    (error = copyin(uap->oldlenp, &oldlen, sizeof(oldlen))))
141		return (error);
142	if (uap->old != NULL) {
143		if (!useracc(uap->old, oldlen, B_WRITE))
144			return (EFAULT);
145		while (memlock.sl_lock) {
146			memlock.sl_want = 1;
147			sleep((caddr_t)&memlock, PRIBIO+1);
148			memlock.sl_locked++;
149		}
150		memlock.sl_lock = 1;
151		if (dolock)
152			vslock(uap->old, oldlen);
153		savelen = oldlen;
154	}
155	error = (*fn)(name + 1, uap->namelen - 1, uap->old, &oldlen,
156	    uap->new, uap->newlen, p);
157	if (uap->old != NULL) {
158		if (dolock)
159			vsunlock(uap->old, savelen, B_WRITE);
160		memlock.sl_lock = 0;
161		if (memlock.sl_want) {
162			memlock.sl_want = 0;
163			wakeup((caddr_t)&memlock);
164		}
165	}
166	if (error)
167		return (error);
168	if (uap->oldlenp)
169		error = copyout(&oldlen, uap->oldlenp, sizeof(oldlen));
170	*retval = oldlen;
171	return (0);
172}
173
174/*
175 * Attributes stored in the kernel.
176 */
177char hostname[MAXHOSTNAMELEN];
178int hostnamelen;
179char domainname[MAXHOSTNAMELEN];
180int domainnamelen;
181long hostid;
182int securelevel;
183
184/*
185 * kernel related system variables.
186 */
187int
188kern_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
189	int *name;
190	u_int namelen;
191	void *oldp;
192	size_t *oldlenp;
193	void *newp;
194	size_t newlen;
195	struct proc *p;
196{
197	int error, level, inthostid;
198	extern char ostype[], osrelease[], version[];
199
200	/* all sysctl names at this level are terminal */
201	if (namelen != 1 && !(name[0] == KERN_PROC || name[0] == KERN_PROF))
202		return (ENOTDIR);		/* overloaded */
203
204	switch (name[0]) {
205	case KERN_OSTYPE:
206		return (sysctl_rdstring(oldp, oldlenp, newp, ostype));
207	case KERN_OSRELEASE:
208		return (sysctl_rdstring(oldp, oldlenp, newp, osrelease));
209	case KERN_OSREV:
210		return (sysctl_rdint(oldp, oldlenp, newp, BSD));
211	case KERN_VERSION:
212		return (sysctl_rdstring(oldp, oldlenp, newp, version));
213	case KERN_MAXVNODES:
214		return(sysctl_int(oldp, oldlenp, newp, newlen, &desiredvnodes));
215	case KERN_MAXPROC:
216		return (sysctl_int(oldp, oldlenp, newp, newlen, &maxproc));
217	case KERN_MAXFILES:
218		return (sysctl_int(oldp, oldlenp, newp, newlen, &maxfiles));
219	case KERN_ARGMAX:
220		return (sysctl_rdint(oldp, oldlenp, newp, ARG_MAX));
221	case KERN_SECURELVL:
222		level = securelevel;
223		if ((error = sysctl_int(oldp, oldlenp, newp, newlen, &level)) ||
224		    newp == NULL)
225			return (error);
226		if (level < securelevel && p->p_pid != 1)
227			return (EPERM);
228		securelevel = level;
229		return (0);
230	case KERN_HOSTNAME:
231		error = sysctl_string(oldp, oldlenp, newp, newlen,
232		    hostname, sizeof(hostname));
233		if (newp && !error)
234			hostnamelen = newlen;
235		return (error);
236	case KERN_DOMAINNAME:
237		error = sysctl_string(oldp, oldlenp, newp, newlen,
238		    domainname, sizeof(domainname));
239		if (newp && !error)
240			domainnamelen = newlen;
241		return (error);
242	case KERN_HOSTID:
243		inthostid = hostid;  /* XXX assumes sizeof long <= sizeof int */
244		error =  sysctl_int(oldp, oldlenp, newp, newlen, &inthostid);
245		hostid = inthostid;
246		return (error);
247	case KERN_CLOCKRATE:
248		return (sysctl_clockrate(oldp, oldlenp));
249	case KERN_BOOTTIME:
250		return (sysctl_rdstruct(oldp, oldlenp, newp, &boottime,
251		    sizeof(struct timeval)));
252	case KERN_VNODE:
253		return (sysctl_vnode(oldp, oldlenp));
254	case KERN_PROC:
255		return (sysctl_doproc(name + 1, namelen - 1, oldp, oldlenp));
256	case KERN_FILE:
257		return (sysctl_file(oldp, oldlenp));
258#ifdef GPROF
259	case KERN_PROF:
260		return (sysctl_doprof(name + 1, namelen - 1, oldp, oldlenp,
261		    newp, newlen));
262#endif
263	case KERN_POSIX1:
264		return (sysctl_rdint(oldp, oldlenp, newp, _POSIX_VERSION));
265	case KERN_NGROUPS:
266		return (sysctl_rdint(oldp, oldlenp, newp, NGROUPS_MAX));
267	case KERN_JOB_CONTROL:
268		return (sysctl_rdint(oldp, oldlenp, newp, 1));
269	case KERN_SAVED_IDS:
270#ifdef _POSIX_SAVED_IDS
271		return (sysctl_rdint(oldp, oldlenp, newp, 1));
272#else
273		return (sysctl_rdint(oldp, oldlenp, newp, 0));
274#endif
275	default:
276		return (EOPNOTSUPP);
277	}
278	/* NOTREACHED */
279}
280
281/*
282 * hardware related system variables.
283 */
284int
285hw_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
286	int *name;
287	u_int namelen;
288	void *oldp;
289	size_t *oldlenp;
290	void *newp;
291	size_t newlen;
292	struct proc *p;
293{
294	extern char machine[], cpu_model[];
295
296	/* all sysctl names at this level are terminal */
297	if (namelen != 1)
298		return (ENOTDIR);		/* overloaded */
299
300	switch (name[0]) {
301	case HW_MACHINE:
302		return (sysctl_rdstring(oldp, oldlenp, newp, machine));
303	case HW_MODEL:
304		return (sysctl_rdstring(oldp, oldlenp, newp, cpu_model));
305	case HW_NCPU:
306		return (sysctl_rdint(oldp, oldlenp, newp, 1));	/* XXX */
307	case HW_BYTEORDER:
308		return (sysctl_rdint(oldp, oldlenp, newp, BYTE_ORDER));
309	case HW_PHYSMEM:
310		return (sysctl_rdint(oldp, oldlenp, newp, ctob(physmem)));
311	case HW_USERMEM:
312		return (sysctl_rdint(oldp, oldlenp, newp,
313		    ctob(physmem - cnt.v_wire_count)));
314	case HW_PAGESIZE:
315		return (sysctl_rdint(oldp, oldlenp, newp, PAGE_SIZE));
316	default:
317		return (EOPNOTSUPP);
318	}
319	/* NOTREACHED */
320}
321
322#ifdef DEBUG
323/*
324 * Debugging related system variables.
325 */
326struct ctldebug debug0, debug1, debug2, debug3, debug4;
327struct ctldebug debug5, debug6, debug7, debug8, debug9;
328struct ctldebug debug10, debug11, debug12, debug13, debug14;
329struct ctldebug debug15, debug16, debug17, debug18, debug19;
330static struct ctldebug *debugvars[CTL_DEBUG_MAXID] = {
331	&debug0, &debug1, &debug2, &debug3, &debug4,
332	&debug5, &debug6, &debug7, &debug8, &debug9,
333	&debug10, &debug11, &debug12, &debug13, &debug14,
334	&debug15, &debug16, &debug17, &debug18, &debug19,
335};
336int
337debug_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
338	int *name;
339	u_int namelen;
340	void *oldp;
341	size_t *oldlenp;
342	void *newp;
343	size_t newlen;
344	struct proc *p;
345{
346	struct ctldebug *cdp;
347
348	/* all sysctl names at this level are name and field */
349	if (namelen != 2)
350		return (ENOTDIR);		/* overloaded */
351	cdp = debugvars[name[0]];
352	if (cdp->debugname == 0)
353		return (EOPNOTSUPP);
354	switch (name[1]) {
355	case CTL_DEBUG_NAME:
356		return (sysctl_rdstring(oldp, oldlenp, newp, cdp->debugname));
357	case CTL_DEBUG_VALUE:
358		return (sysctl_int(oldp, oldlenp, newp, newlen, cdp->debugvar));
359	default:
360		return (EOPNOTSUPP);
361	}
362	/* NOTREACHED */
363}
364#endif /* DEBUG */
365
366/*
367 * Validate parameters and get old / set new parameters
368 * for an integer-valued sysctl function.
369 */
370int
371sysctl_int(oldp, oldlenp, newp, newlen, valp)
372	void *oldp;
373	size_t *oldlenp;
374	void *newp;
375	size_t newlen;
376	int *valp;
377{
378	int error = 0;
379
380	if (oldp && *oldlenp < sizeof(int))
381		return (ENOMEM);
382	if (newp && newlen != sizeof(int))
383		return (EINVAL);
384	*oldlenp = sizeof(int);
385	if (oldp)
386		error = copyout(valp, oldp, sizeof(int));
387	if (error == 0 && newp)
388		error = copyin(newp, valp, sizeof(int));
389	return (error);
390}
391
392/*
393 * As above, but read-only.
394 */
395int
396sysctl_rdint(oldp, oldlenp, newp, val)
397	void *oldp;
398	size_t *oldlenp;
399	void *newp;
400	int val;
401{
402	int error = 0;
403
404	if (oldp && *oldlenp < sizeof(int))
405		return (ENOMEM);
406	if (newp)
407		return (EPERM);
408	*oldlenp = sizeof(int);
409	if (oldp)
410		error = copyout((caddr_t)&val, oldp, sizeof(int));
411	return (error);
412}
413
414/*
415 * Validate parameters and get old / set new parameters
416 * for a string-valued sysctl function.
417 */
418int
419sysctl_string(oldp, oldlenp, newp, newlen, str, maxlen)
420	void *oldp;
421	size_t *oldlenp;
422	void *newp;
423	size_t newlen;
424	char *str;
425	int maxlen;
426{
427	int len, error = 0;
428
429	len = strlen(str) + 1;
430	if (oldp && *oldlenp < len)
431		return (ENOMEM);
432	if (newp && newlen >= maxlen)
433		return (EINVAL);
434	if (oldp) {
435		*oldlenp = len;
436		error = copyout(str, oldp, len);
437	}
438	if (error == 0 && newp) {
439		error = copyin(newp, str, newlen);
440		str[newlen] = 0;
441	}
442	return (error);
443}
444
445/*
446 * As above, but read-only.
447 */
448int
449sysctl_rdstring(oldp, oldlenp, newp, str)
450	void *oldp;
451	size_t *oldlenp;
452	void *newp;
453	char *str;
454{
455	int len, error = 0;
456
457	len = strlen(str) + 1;
458	if (oldp && *oldlenp < len)
459		return (ENOMEM);
460	if (newp)
461		return (EPERM);
462	*oldlenp = len;
463	if (oldp)
464		error = copyout(str, oldp, len);
465	return (error);
466}
467
468/*
469 * Validate parameters and get old / set new parameters
470 * for a structure oriented sysctl function.
471 */
472int
473sysctl_struct(oldp, oldlenp, newp, newlen, sp, len)
474	void *oldp;
475	size_t *oldlenp;
476	void *newp;
477	size_t newlen;
478	void *sp;
479	int len;
480{
481	int error = 0;
482
483	if (oldp && *oldlenp < len)
484		return (ENOMEM);
485	if (newp && newlen > len)
486		return (EINVAL);
487	if (oldp) {
488		*oldlenp = len;
489		error = copyout(sp, oldp, len);
490	}
491	if (error == 0 && newp)
492		error = copyin(newp, sp, len);
493	return (error);
494}
495
496/*
497 * Validate parameters and get old parameters
498 * for a structure oriented sysctl function.
499 */
500int
501sysctl_rdstruct(oldp, oldlenp, newp, sp, len)
502	void *oldp;
503	size_t *oldlenp;
504	void *newp, *sp;
505	int len;
506{
507	int error = 0;
508
509	if (oldp && *oldlenp < len)
510		return (ENOMEM);
511	if (newp)
512		return (EPERM);
513	*oldlenp = len;
514	if (oldp)
515		error = copyout(sp, oldp, len);
516	return (error);
517}
518
519/*
520 * Get file structures.
521 */
522int
523sysctl_file(where, sizep)
524	char *where;
525	size_t *sizep;
526{
527	int buflen, error;
528	struct file *fp;
529	char *start = where;
530
531	buflen = *sizep;
532	if (where == NULL) {
533		/*
534		 * overestimate by 10 files
535		 */
536		*sizep = sizeof(filehead) + (nfiles + 10) * sizeof(struct file);
537		return (0);
538	}
539
540	/*
541	 * first copyout filehead
542	 */
543	if (buflen < sizeof(filehead)) {
544		*sizep = 0;
545		return (0);
546	}
547	if (error = copyout((caddr_t)&filehead, where, sizeof(filehead)))
548		return (error);
549	buflen -= sizeof(filehead);
550	where += sizeof(filehead);
551
552	/*
553	 * followed by an array of file structures
554	 */
555	for (fp = filehead; fp != NULL; fp = fp->f_filef) {
556		if (buflen < sizeof(struct file)) {
557			*sizep = where - start;
558			return (ENOMEM);
559		}
560		if (error = copyout((caddr_t)fp, where, sizeof (struct file)))
561			return (error);
562		buflen -= sizeof(struct file);
563		where += sizeof(struct file);
564	}
565	*sizep = where - start;
566	return (0);
567}
568
569/*
570 * try over estimating by 5 procs
571 */
572#define KERN_PROCSLOP	(5 * sizeof (struct kinfo_proc))
573
574int
575sysctl_doproc(name, namelen, where, sizep)
576	int *name;
577	u_int namelen;
578	char *where;
579	size_t *sizep;
580{
581	register struct proc *p;
582	register struct kinfo_proc *dp = (struct kinfo_proc *)where;
583	register int needed = 0;
584	int buflen = where != NULL ? *sizep : 0;
585	int doingzomb;
586	struct eproc eproc;
587	int error = 0;
588
589	if (namelen != 2 && !(namelen == 1 && name[0] == KERN_PROC_ALL))
590		return (EINVAL);
591	p = (struct proc *)allproc;
592	doingzomb = 0;
593again:
594	for (; p != NULL; p = p->p_next) {
595		/*
596		 * Skip embryonic processes.
597		 */
598		if (p->p_stat == SIDL)
599			continue;
600		/*
601		 * TODO - make more efficient (see notes below).
602		 * do by session.
603		 */
604		switch (name[0]) {
605
606		case KERN_PROC_PID:
607			/* could do this with just a lookup */
608			if (p->p_pid != (pid_t)name[1])
609				continue;
610			break;
611
612		case KERN_PROC_PGRP:
613			/* could do this by traversing pgrp */
614			if (p->p_pgrp->pg_id != (pid_t)name[1])
615				continue;
616			break;
617
618		case KERN_PROC_TTY:
619			if ((p->p_flag & P_CONTROLT) == 0 ||
620			    p->p_session->s_ttyp == NULL ||
621			    p->p_session->s_ttyp->t_dev != (dev_t)name[1])
622				continue;
623			break;
624
625		case KERN_PROC_UID:
626			if (p->p_ucred->cr_uid != (uid_t)name[1])
627				continue;
628			break;
629
630		case KERN_PROC_RUID:
631			if (p->p_cred->p_ruid != (uid_t)name[1])
632				continue;
633			break;
634		}
635		if (buflen >= sizeof(struct kinfo_proc)) {
636			fill_eproc(p, &eproc);
637			if (error = copyout((caddr_t)p, &dp->kp_proc,
638			    sizeof(struct proc)))
639				return (error);
640			if (error = copyout((caddr_t)&eproc, &dp->kp_eproc,
641			    sizeof(eproc)))
642				return (error);
643			dp++;
644			buflen -= sizeof(struct kinfo_proc);
645		}
646		needed += sizeof(struct kinfo_proc);
647	}
648	if (doingzomb == 0) {
649		p = zombproc;
650		doingzomb++;
651		goto again;
652	}
653	if (where != NULL) {
654		*sizep = (caddr_t)dp - where;
655		if (needed > *sizep)
656			return (ENOMEM);
657	} else {
658		needed += KERN_PROCSLOP;
659		*sizep = needed;
660	}
661	return (0);
662}
663
664/*
665 * Fill in an eproc structure for the specified process.
666 */
667void
668fill_eproc(p, ep)
669	register struct proc *p;
670	register struct eproc *ep;
671{
672	register struct tty *tp;
673
674	ep->e_paddr = p;
675	ep->e_sess = p->p_pgrp->pg_session;
676	ep->e_pcred = *p->p_cred;
677	ep->e_ucred = *p->p_ucred;
678	if (p->p_stat == SIDL || p->p_stat == SZOMB) {
679		ep->e_vm.vm_rssize = 0;
680		ep->e_vm.vm_tsize = 0;
681		ep->e_vm.vm_dsize = 0;
682		ep->e_vm.vm_ssize = 0;
683#ifndef sparc
684		/* ep->e_vm.vm_pmap = XXX; */
685#endif
686	} else {
687		register struct vmspace *vm = p->p_vmspace;
688
689#ifdef pmap_resident_count
690		ep->e_vm.vm_rssize = pmap_resident_count(&vm->vm_pmap); /*XXX*/
691#else
692		ep->e_vm.vm_rssize = vm->vm_rssize;
693#endif
694		ep->e_vm.vm_tsize = vm->vm_tsize;
695		ep->e_vm.vm_dsize = vm->vm_dsize;
696		ep->e_vm.vm_ssize = vm->vm_ssize;
697#ifndef sparc
698		ep->e_vm.vm_pmap = vm->vm_pmap;
699#endif
700	}
701	if (p->p_pptr)
702		ep->e_ppid = p->p_pptr->p_pid;
703	else
704		ep->e_ppid = 0;
705	ep->e_pgid = p->p_pgrp->pg_id;
706	ep->e_jobc = p->p_pgrp->pg_jobc;
707	if ((p->p_flag & P_CONTROLT) &&
708	     (tp = ep->e_sess->s_ttyp)) {
709		ep->e_tdev = tp->t_dev;
710		ep->e_tpgid = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID;
711		ep->e_tsess = tp->t_session;
712	} else
713		ep->e_tdev = NODEV;
714	ep->e_flag = ep->e_sess->s_ttyvp ? EPROC_CTTY : 0;
715	if (SESS_LEADER(p))
716		ep->e_flag |= EPROC_SLEADER;
717	if (p->p_wmesg)
718		strncpy(ep->e_wmesg, p->p_wmesg, WMESGLEN);
719	ep->e_xsize = ep->e_xrssize = 0;
720	ep->e_xccount = ep->e_xswrss = 0;
721}
722
723#ifdef COMPAT_43
724#include <sys/socket.h>
725#define	KINFO_PROC		(0<<8)
726#define	KINFO_RT		(1<<8)
727#define	KINFO_VNODE		(2<<8)
728#define	KINFO_FILE		(3<<8)
729#define	KINFO_METER		(4<<8)
730#define	KINFO_LOADAVG		(5<<8)
731#define	KINFO_CLOCKRATE		(6<<8)
732
733struct getkerninfo_args {
734	int	op;
735	char	*where;
736	int	*size;
737	int	arg;
738};
739
740int
741ogetkerninfo(p, uap, retval)
742	struct proc *p;
743	register struct getkerninfo_args *uap;
744	int *retval;
745{
746	int error, name[5];
747	u_int size;
748
749	if (uap->size &&
750	    (error = copyin((caddr_t)uap->size, (caddr_t)&size, sizeof(size))))
751		return (error);
752
753	switch (uap->op & 0xff00) {
754
755	case KINFO_RT:
756		name[0] = PF_ROUTE;
757		name[1] = 0;
758		name[2] = (uap->op & 0xff0000) >> 16;
759		name[3] = uap->op & 0xff;
760		name[4] = uap->arg;
761		error = net_sysctl(name, 5, uap->where, &size, NULL, 0, p);
762		break;
763
764	case KINFO_VNODE:
765		name[0] = KERN_VNODE;
766		error = kern_sysctl(name, 1, uap->where, &size, NULL, 0, p);
767		break;
768
769	case KINFO_PROC:
770		name[0] = KERN_PROC;
771		name[1] = uap->op & 0xff;
772		name[2] = uap->arg;
773		error = kern_sysctl(name, 3, uap->where, &size, NULL, 0, p);
774		break;
775
776	case KINFO_FILE:
777		name[0] = KERN_FILE;
778		error = kern_sysctl(name, 1, uap->where, &size, NULL, 0, p);
779		break;
780
781	case KINFO_METER:
782		name[0] = VM_METER;
783		error = vm_sysctl(name, 1, uap->where, &size, NULL, 0, p);
784		break;
785
786	case KINFO_LOADAVG:
787		name[0] = VM_LOADAVG;
788		error = vm_sysctl(name, 1, uap->where, &size, NULL, 0, p);
789		break;
790
791	case KINFO_CLOCKRATE:
792		name[0] = KERN_CLOCKRATE;
793		error = kern_sysctl(name, 1, uap->where, &size, NULL, 0, p);
794		break;
795
796	default:
797		return (EOPNOTSUPP);
798	}
799	if (error)
800		return (error);
801	*retval = size;
802	if (uap->size)
803		error = copyout((caddr_t)&size, (caddr_t)uap->size,
804		    sizeof(size));
805	return (error);
806}
807#endif /* COMPAT_43 */
808