kern_sysctl.c revision 12221
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.36 1995/11/11 00:09:21 bde Exp $
38 */
39
40/*
41 * sysctl system call.
42 */
43
44#include <sys/param.h>
45#include <sys/systm.h>
46#include <sys/sysproto.h>
47#include <sys/kernel.h>
48#include <sys/malloc.h>
49#include <sys/proc.h>
50#include <sys/file.h>
51#include <sys/vnode.h>
52#include <sys/unistd.h>
53#include <sys/buf.h>
54#include <sys/ioctl.h>
55#include <sys/tty.h>
56#include <sys/conf.h>
57#include <vm/vm.h>
58#include <sys/sysctl.h>
59#include <sys/user.h>
60
61extern struct linker_set sysctl_;
62
63/* BEGIN_MIB */
64SYSCTL_NODE(, 0,	  sysctl, CTLFLAG_RW, 0,
65	"Sysctl internal magic");
66SYSCTL_NODE(, CTL_KERN,	  kern,   CTLFLAG_RW, 0,
67	"High kernel, proc, limits &c");
68SYSCTL_NODE(, CTL_VM,	  vm,     CTLFLAG_RW, 0,
69	"Virtual memory");
70SYSCTL_NODE(, CTL_FS,	  fs,     CTLFLAG_RW, 0,
71	"File system");
72SYSCTL_NODE(, CTL_NET,	  net,    CTLFLAG_RW, 0,
73	"Network, (see socket.h)");
74SYSCTL_NODE(, CTL_DEBUG,  debug,  CTLFLAG_RW, 0,
75	"Debugging");
76SYSCTL_NODE(, CTL_HW,	  hw,     CTLFLAG_RW, 0,
77	"hardware");
78SYSCTL_NODE(, CTL_MACHDEP, machdep, CTLFLAG_RW, 0,
79	"machine dependent");
80SYSCTL_NODE(, CTL_USER,	  user,   CTLFLAG_RW, 0,
81	"user-level");
82
83SYSCTL_STRING(_kern, KERN_OSRELEASE, osrelease, CTLFLAG_RD, osrelease, 0, "");
84
85SYSCTL_INT(_kern, KERN_OSREV, osrevision, CTLFLAG_RD, 0, BSD, "");
86
87SYSCTL_STRING(_kern, KERN_VERSION, version, CTLFLAG_RD, version, 0, "");
88
89SYSCTL_STRING(_kern, KERN_OSTYPE, ostype, CTLFLAG_RD, ostype, 0, "");
90
91extern int osreldate;
92SYSCTL_INT(_kern, KERN_OSRELDATE, osreldate, CTLFLAG_RD, &osreldate, 0, "");
93
94SYSCTL_INT(_kern, KERN_MAXVNODES, maxvnodes, CTLFLAG_RD, &desiredvnodes, 0, "");
95
96SYSCTL_INT(_kern, KERN_MAXPROC, maxproc, CTLFLAG_RD, &maxproc, 0, "");
97
98SYSCTL_INT(_kern, KERN_MAXPROCPERUID, maxprocperuid,
99	CTLFLAG_RD, &maxprocperuid, 0, "");
100
101SYSCTL_INT(_kern, KERN_MAXFILESPERPROC, maxfilesperproc,
102	CTLFLAG_RD, &maxfilesperproc, 0, "");
103
104SYSCTL_INT(_kern, KERN_ARGMAX, argmax, CTLFLAG_RD, 0, ARG_MAX, "");
105
106SYSCTL_INT(_kern, KERN_POSIX1, posix1version, CTLFLAG_RD, 0, _POSIX_VERSION, "");
107
108SYSCTL_INT(_kern, KERN_NGROUPS, ngroups, CTLFLAG_RD, 0, NGROUPS_MAX, "");
109
110SYSCTL_INT(_kern, KERN_JOB_CONTROL, job_control, CTLFLAG_RD, 0, 1, "");
111
112SYSCTL_INT(_kern, KERN_MAXFILES, maxfiles, CTLFLAG_RW, &maxfiles, 0, "");
113
114#ifdef _POSIX_SAVED_IDS
115SYSCTL_INT(_kern, KERN_SAVED_IDS, saved_ids, CTLFLAG_RD, 0, 1, "");
116#else
117SYSCTL_INT(_kern, KERN_SAVED_IDS, saved_ids, CTLFLAG_RD, 0, 0, "");
118#endif
119
120char kernelname[MAXPATHLEN] = "/kernel";	/* XXX bloat */
121
122SYSCTL_STRING(_kern, KERN_BOOTFILE, bootfile,
123	CTLFLAG_RW, kernelname, sizeof kernelname, "");
124
125SYSCTL_STRUCT(_kern, KERN_BOOTTIME, boottime,
126	CTLFLAG_RW, &boottime, timeval, "");
127
128SYSCTL_STRING(_hw, HW_MACHINE, machine, CTLFLAG_RD, machine, 0, "");
129
130SYSCTL_STRING(_hw, HW_MODEL, model, CTLFLAG_RD, cpu_model, 0, "");
131
132SYSCTL_INT(_hw, HW_NCPU, ncpu, CTLFLAG_RD, 0, 1, "");
133
134SYSCTL_INT(_hw, HW_BYTEORDER, byteorder, CTLFLAG_RD, 0, BYTE_ORDER, "");
135
136SYSCTL_INT(_hw, HW_PAGESIZE, pagesize, CTLFLAG_RD, 0, PAGE_SIZE, "");
137
138/* END_MIB */
139
140extern int vfs_update_wakeup;
141extern int vfs_update_interval;
142static int
143sysctl_kern_updateinterval SYSCTL_HANDLER_ARGS
144{
145	int error = sysctl_handle_int(oidp,
146		oidp->oid_arg1, oidp->oid_arg2,
147		oldp, oldlenp, newp, newlen);
148	if (!error)
149		wakeup(&vfs_update_wakeup);
150	return error;
151}
152
153SYSCTL_PROC(_kern, KERN_UPDATEINTERVAL, update, CTLTYPE_INT|CTLFLAG_RW,
154	&vfs_update_interval, 0, sysctl_kern_updateinterval, "");
155
156
157char hostname[MAXHOSTNAMELEN];
158int hostnamelen;
159static int
160sysctl_kern_hostname SYSCTL_HANDLER_ARGS
161{
162	int error = sysctl_handle_string(oidp,
163		oidp->oid_arg1, oidp->oid_arg2,
164		oldp, oldlenp, newp, newlen);
165	if (newp && (error == 0 || error == ENOMEM))
166		hostnamelen = newlen;
167	return error;
168}
169
170SYSCTL_PROC(_kern, KERN_HOSTNAME, hostname, CTLTYPE_STRING|CTLFLAG_RW,
171	&hostname, sizeof(hostname), sysctl_kern_hostname, "");
172
173static int
174sysctl_order_cmp(const void *a, const void *b)
175{
176	const struct sysctl_oid **pa, **pb;
177
178	pa = (const struct sysctl_oid **)a;
179	pb = (const struct sysctl_oid **)b;
180	if (*pa == NULL)
181		return (1);
182	if (*pb == NULL)
183		return (-1);
184	return ((*pa)->oid_number - (*pb)->oid_number);
185}
186
187static void
188sysctl_order(void *arg)
189{
190	int j;
191	struct linker_set *l = (struct linker_set *) arg;
192	struct sysctl_oid **oidpp;
193
194	j = l->ls_length;
195	oidpp = (struct sysctl_oid **) l->ls_items;
196	for (; j--; oidpp++) {
197		if (!*oidpp)
198			continue;
199		if ((*oidpp)->oid_arg1 == arg) {
200			*oidpp = 0;
201			continue;
202		}
203		if (((*oidpp)->oid_kind & CTLTYPE) == CTLTYPE_NODE)
204			if (!(*oidpp)->oid_handler)
205				sysctl_order((*oidpp)->oid_arg1);
206	}
207	qsort(l->ls_items, l->ls_length, sizeof l->ls_items[0],
208		sysctl_order_cmp);
209}
210
211SYSINIT(sysctl,SI_SUB_KMEM,SI_ORDER_ANY,sysctl_order,&sysctl_);
212
213static void
214sysctl_sysctl_debug_dump_node(struct linker_set *l,int i)
215{
216	int j,k;
217	struct sysctl_oid **oidpp;
218
219	j = l->ls_length;
220	oidpp = (struct sysctl_oid **) l->ls_items;
221	for (; j--; oidpp++) {
222
223		if (!*oidpp)
224			continue;
225
226		for (k=0; k<i; k++)
227			printf(" ");
228
229		if ((*oidpp)->oid_number > 100) {
230			printf("Junk! %p  # %d  %s  k %x  a1 %p  a2 %x  h %p\n",
231				*oidpp,
232		 		(*oidpp)->oid_number, (*oidpp)->oid_name,
233		 		(*oidpp)->oid_kind, (*oidpp)->oid_arg1,
234		 		(*oidpp)->oid_arg2, (*oidpp)->oid_handler);
235			continue;
236		}
237		printf("%d %s ", (*oidpp)->oid_number, (*oidpp)->oid_name);
238
239		printf("%c%c",
240			(*oidpp)->oid_kind & CTLFLAG_RD ? 'R':' ',
241			(*oidpp)->oid_kind & CTLFLAG_WR ? 'W':' ');
242
243		switch ((*oidpp)->oid_kind & CTLTYPE) {
244			case CTLTYPE_NODE:
245				if ((*oidpp)->oid_handler) {
246					printf(" Node(proc)\n");
247				} else {
248					printf(" Node\n");
249					sysctl_sysctl_debug_dump_node(
250						(*oidpp)->oid_arg1,i+2);
251				}
252				break;
253			case CTLTYPE_INT:    printf(" Int\n"); break;
254			case CTLTYPE_STRING: printf(" String\n"); break;
255			case CTLTYPE_QUAD:   printf(" Quad\n"); break;
256			case CTLTYPE_OPAQUE: printf(" Opaque/struct\n"); break;
257			default:	     printf("\n");
258		}
259
260	}
261}
262
263
264static int
265sysctl_sysctl_debug SYSCTL_HANDLER_ARGS
266{
267	sysctl_sysctl_debug_dump_node(&sysctl_,0);
268	return ENOENT;
269}
270
271SYSCTL_PROC(_sysctl, 0, debug, CTLTYPE_STRING|CTLFLAG_RD,
272	0, 0, sysctl_sysctl_debug, "");
273
274char domainname[MAXHOSTNAMELEN];
275int domainnamelen;
276static int
277sysctl_kern_domainname SYSCTL_HANDLER_ARGS
278{
279	int error = sysctl_handle_string(oidp,
280		oidp->oid_arg1, oidp->oid_arg2,
281		oldp, oldlenp, newp, newlen);
282	if (newp && (error == 0 || error == ENOMEM))
283		domainnamelen = newlen;
284	return error;
285}
286
287SYSCTL_PROC(_kern, KERN_DOMAINNAME, domainname, CTLTYPE_STRING|CTLFLAG_RW,
288	&domainname, sizeof(domainname), sysctl_kern_domainname, "");
289
290long hostid;
291/* Some trouble here, if sizeof (int) != sizeof (long) */
292SYSCTL_INT(_kern, KERN_HOSTID, hostid, CTLFLAG_RW, &hostid, 0, "");
293
294int
295sysctl_handle_int SYSCTL_HANDLER_ARGS
296{
297	/* If there isn't sufficient space to return */
298	if (oldp && *oldlenp < sizeof(int))
299		return (ENOMEM);
300
301	/* If it is a constant, don't write */
302	if (newp && !arg1)
303		return (EPERM);
304
305	/* If we get more than an int */
306	if (newp && newlen != sizeof(int))
307		return (EINVAL);
308
309	*oldlenp = sizeof(int);
310	if (oldp && arg1 )
311		bcopy(arg1, oldp, sizeof(int));
312	else if (oldp)
313		bcopy(&arg2, oldp, sizeof(int));
314	if (newp)
315		bcopy(newp, arg1, sizeof(int));
316	return (0);
317}
318
319int
320sysctl_handle_string SYSCTL_HANDLER_ARGS
321{
322	int len, error=0;
323	char *str = (char *)arg1;
324
325	len = strlen(str) + 1;
326
327	if (oldp && *oldlenp < len) {
328		len = *oldlenp;
329		error=ENOMEM;
330	}
331
332	if (newp && newlen >= arg2)
333		return (EINVAL);
334
335	if (oldp) {
336		*oldlenp = len;
337		bcopy(str, oldp, len);
338	}
339
340	if (newp) {
341		bcopy(newp, str, newlen);
342		str[newlen] = 0;
343	}
344	return (error);
345}
346
347int
348sysctl_handle_opaque SYSCTL_HANDLER_ARGS
349{
350	if (oldp && *oldlenp < arg2)
351		return (ENOMEM);
352
353	if (newp && newlen != arg2)
354		return (EINVAL);
355
356	if (oldp) {
357		*oldlenp = arg2;
358		bcopy(arg1, oldp, arg2);
359	}
360	if (newp)
361		bcopy(newp, arg1, arg2);
362	return (0);
363}
364
365#ifdef DEBUG
366static sysctlfn debug_sysctl;
367#endif
368
369/*
370 * Locking and stats
371 */
372static struct sysctl_lock {
373	int	sl_lock;
374	int	sl_want;
375	int	sl_locked;
376} memlock;
377
378
379
380/*
381 * Traverse our tree, and find the right node, execute whatever it points
382 * at, and return the resulting error code.
383 * We work entirely in kernel-space at this time.
384 */
385
386
387int
388sysctl_root SYSCTL_HANDLER_ARGS
389{
390	int *name = (int *) arg1;
391	int namelen = arg2;
392	int indx, i, j;
393	struct sysctl_oid **oidpp;
394	struct linker_set *lsp = &sysctl_;
395
396	j = lsp->ls_length;
397	oidpp = (struct sysctl_oid **) lsp->ls_items;
398
399	indx = 0;
400	while (j-- && indx < CTL_MAXNAME) {
401		if (*oidpp && ((*oidpp)->oid_number == name[indx])) {
402			indx++;
403			if (((*oidpp)->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
404				if ((*oidpp)->oid_handler)
405					goto found;
406				if (indx == namelen)
407					return ENOENT;
408				lsp = (struct linker_set*)(*oidpp)->oid_arg1;
409				j = lsp->ls_length;
410				oidpp = (struct sysctl_oid **)lsp->ls_items;
411			} else {
412				if (indx != namelen)
413					return EISDIR;
414				goto found;
415			}
416		} else {
417			oidpp++;
418		}
419	}
420	return EJUSTRETURN;
421found:
422
423	/* If writing isn't allowed */
424	if (newp && !((*oidpp)->oid_kind & CTLFLAG_WR))
425		return (EPERM);
426
427	if (!(*oidpp)->oid_handler)
428		return EINVAL;
429
430	if (((*oidpp)->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
431		i = ((*oidpp)->oid_handler) (*oidpp,
432					name + indx, namelen - indx,
433					oldp, oldlenp, newp, newlen);
434	} else {
435		i = ((*oidpp)->oid_handler) (*oidpp,
436					(*oidpp)->oid_arg1, (*oidpp)->oid_arg2,
437					oldp, oldlenp, newp, newlen);
438	}
439	return (i);
440}
441
442#ifndef _SYS_SYSPROTO_H_
443struct sysctl_args {
444	int	*name;
445	u_int	namelen;
446	void	*old;
447	size_t	*oldlenp;
448	void	*new;
449	size_t	newlen;
450};
451#endif
452
453int
454__sysctl(p, uap, retval)
455	struct proc *p;
456	register struct sysctl_args *uap;
457	int *retval;
458{
459	int error, name[CTL_MAXNAME];
460
461	if (uap->namelen > CTL_MAXNAME || uap->namelen < 2)
462		return (EINVAL);
463
464 	error = copyin(uap->name, &name, uap->namelen * sizeof(int));
465 	if (error)
466		return (error);
467
468	return (userland_sysctl(p, name, uap->namelen,
469		uap->old, uap->oldlenp, 0,
470		uap->new, uap->newlen, retval));
471}
472
473static sysctlfn kern_sysctl;
474
475/*
476 * This is used from various compatibility syscalls too.  That's why name
477 * must be in kernel space.
478 */
479int
480userland_sysctl(struct proc *p, int *name, u_int namelen, void *old, size_t *oldlenp, int inkernel, void *new, size_t newlen, int *retval)
481{
482	int error = 0, dolock = 1, i;
483	u_int savelen = 0, oldlen = 0;
484	sysctlfn *fn;
485	void *oldp = 0;
486	void *newp = 0;
487
488	if (new != NULL && (error = suser(p->p_ucred, &p->p_acflag)))
489		return (error);
490
491	if (oldlenp) {
492		if (inkernel) {
493			oldlen = *oldlenp;
494		} else {
495			error = copyin(oldlenp, &oldlen, sizeof(oldlen));
496			if (error)
497				return (error);
498		}
499	}
500
501	if (old)
502		oldp = malloc(oldlen, M_TEMP, M_WAITOK);
503
504	if (newlen) {
505		newp = malloc(newlen, M_TEMP, M_WAITOK);
506		error = copyin(new, newp, newlen);
507	}
508	if (error) {
509		if (oldp)
510			free(oldp, M_TEMP);
511		if (newp)
512			free(newp, M_TEMP);
513		return error;
514	}
515
516	error = sysctl_root(0, name, namelen, oldp, &oldlen, newp, newlen);
517
518        if (!error || error == ENOMEM) {
519		if (retval)
520			*retval = oldlen;
521		if (oldlenp) {
522			if (inkernel) {
523				*oldlenp = oldlen;
524			} else {
525				i = copyout(&oldlen, oldlenp, sizeof(oldlen));
526				if (i)
527					error = i;
528			}
529		}
530		if ((error == ENOMEM || !error ) && oldp) {
531			i = copyout(oldp, old, oldlen);
532			if (i)
533				error = i;
534			free(oldp, M_TEMP);
535		}
536		if (newp)
537			free(newp, M_TEMP);
538		return (error);
539	}
540
541	if (oldp)
542		free(oldp, M_TEMP);
543	if (newp)
544		free(newp, M_TEMP);
545
546	switch (name[0]) {
547	case CTL_KERN:
548		fn = kern_sysctl;
549		if (name[1] != KERN_VNODE)      /* XXX */
550			dolock = 0;
551		break;
552	case CTL_HW:
553		fn = hw_sysctl;
554		break;
555	case CTL_VM:
556		fn = vm_sysctl;
557		break;
558	case CTL_NET:
559		fn = net_sysctl;
560		break;
561	case CTL_FS:
562		fn = fs_sysctl;
563		break;
564#ifdef DEBUG
565	case CTL_DEBUG:
566		fn = debug_sysctl;
567		break;
568#endif
569	default:
570		return (EOPNOTSUPP);
571	}
572	if (old != NULL) {
573		if (!useracc(old, oldlen, B_WRITE))
574			return (EFAULT);
575		while (memlock.sl_lock) {
576			memlock.sl_want = 1;
577			(void) tsleep((caddr_t)&memlock, PRIBIO+1, "sysctl", 0);
578			memlock.sl_locked++;
579		}
580		memlock.sl_lock = 1;
581		if (dolock)
582			vslock(old, oldlen);
583		savelen = oldlen;
584	}
585
586
587	error = (*fn)(name + 1, namelen - 1, old, &oldlen,
588	    new, newlen, p);
589
590
591	if (old != NULL) {
592		if (dolock)
593			vsunlock(old, savelen, B_WRITE);
594		memlock.sl_lock = 0;
595		if (memlock.sl_want) {
596			memlock.sl_want = 0;
597			wakeup((caddr_t)&memlock);
598		}
599	}
600#if 0
601	if (error) {
602		printf("SYSCTL_ERROR: ");
603		for(i=0;i<namelen;i++)
604			printf("%d ", name[i]);
605		printf("= %d\n", error);
606	}
607#endif
608	if (error)
609		return (error);
610	if (retval)
611		*retval = oldlen;
612	if (oldlenp) {
613		if (inkernel) {
614			*oldlenp = oldlen;
615		} else {
616			error = copyout(&oldlen, oldlenp, sizeof(oldlen));
617		}
618	}
619	return (error);
620}
621
622/*
623 * Attributes stored in the kernel.
624 */
625int securelevel = -1;
626
627/*
628 * kernel related system variables.
629 */
630static int
631kern_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
632	int *name;
633	u_int namelen;
634	void *oldp;
635	size_t *oldlenp;
636	void *newp;
637	size_t newlen;
638	struct proc *p;
639{
640	int error, level;
641	dev_t ndumpdev;
642
643	/* all sysctl names at this level are terminal */
644	if (namelen != 1 && !(name[0] == KERN_PROC || name[0] == KERN_PROF
645			      || name[0] == KERN_NTP_PLL))
646		return (ENOTDIR);		/* overloaded */
647
648	switch (name[0]) {
649
650	case KERN_SECURELVL:
651		level = securelevel;
652		if ((error = sysctl_int(oldp, oldlenp, newp, newlen, &level)) ||
653		    newp == NULL)
654			return (error);
655		if (level < securelevel && p->p_pid != 1)
656			return (EPERM);
657		securelevel = level;
658		return (0);
659	case KERN_VNODE:
660		return (sysctl_vnode(oldp, oldlenp));
661	case KERN_PROC:
662		return (sysctl_doproc(name + 1, namelen - 1, oldp, oldlenp));
663	case KERN_FILE:
664		return (sysctl_file(oldp, oldlenp));
665#ifdef GPROF
666	case KERN_PROF:
667		return (sysctl_doprof(name + 1, namelen - 1, oldp, oldlenp,
668		    newp, newlen));
669#endif
670	case KERN_NTP_PLL:
671		return (ntp_sysctl(name + 1, namelen - 1, oldp, oldlenp,
672				   newp, newlen, p));
673	case KERN_DUMPDEV:
674		ndumpdev = dumpdev;
675		error = sysctl_struct(oldp, oldlenp, newp, newlen, &ndumpdev,
676				      sizeof ndumpdev);
677		if (!error && ndumpdev != dumpdev) {
678			error = setdumpdev(ndumpdev);
679		}
680		return error;
681	default:
682		return (EOPNOTSUPP);
683	}
684	/* NOTREACHED */
685}
686
687/*
688 * hardware related system variables.
689 */
690int
691hw_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
692	int *name;
693	u_int namelen;
694	void *oldp;
695	size_t *oldlenp;
696	void *newp;
697	size_t newlen;
698	struct proc *p;
699{
700	/* almost all sysctl names at this level are terminal */
701	if (namelen != 1 && name[0] != HW_DEVCONF)
702		return (ENOTDIR);		/* overloaded */
703
704	switch (name[0]) {
705	case HW_PHYSMEM:
706		return (sysctl_rdint(oldp, oldlenp, newp, ctob(physmem)));
707	case HW_USERMEM:
708		return (sysctl_rdint(oldp, oldlenp, newp,
709		    ctob(physmem - cnt.v_wire_count)));
710	case HW_DEVCONF:
711		return (dev_sysctl(name + 1, namelen - 1, oldp, oldlenp,
712				   newp, newlen, p));
713	default:
714		return (EOPNOTSUPP);
715	}
716	/* NOTREACHED */
717}
718
719#ifdef DEBUG
720/*
721 * Debugging related system variables.
722 */
723struct ctldebug debug0, debug1, debug2, debug3, debug4;
724struct ctldebug debug5, debug6, debug7, debug8, debug9;
725struct ctldebug debug10, debug11, debug12, debug13, debug14;
726struct ctldebug debug15, debug16, debug17, debug18, debug19;
727static struct ctldebug *debugvars[CTL_DEBUG_MAXID] = {
728	&debug0, &debug1, &debug2, &debug3, &debug4,
729	&debug5, &debug6, &debug7, &debug8, &debug9,
730	&debug10, &debug11, &debug12, &debug13, &debug14,
731	&debug15, &debug16, &debug17, &debug18, &debug19,
732};
733static int
734debug_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
735	int *name;
736	u_int namelen;
737	void *oldp;
738	size_t *oldlenp;
739	void *newp;
740	size_t newlen;
741	struct proc *p;
742{
743	struct ctldebug *cdp;
744
745	/* all sysctl names at this level are name and field */
746	if (namelen != 2)
747		return (ENOTDIR);		/* overloaded */
748	cdp = debugvars[name[0]];
749	if (cdp->debugname == 0)
750		return (EOPNOTSUPP);
751	switch (name[1]) {
752	case CTL_DEBUG_NAME:
753		return (sysctl_rdstring(oldp, oldlenp, newp, cdp->debugname));
754	case CTL_DEBUG_VALUE:
755		return (sysctl_int(oldp, oldlenp, newp, newlen, cdp->debugvar));
756	default:
757		return (EOPNOTSUPP);
758	}
759	/* NOTREACHED */
760}
761#endif /* DEBUG */
762
763/*
764 * Validate parameters and get old / set new parameters
765 * for an integer-valued sysctl function.
766 */
767int
768sysctl_int(oldp, oldlenp, newp, newlen, valp)
769	void *oldp;
770	size_t *oldlenp;
771	void *newp;
772	size_t newlen;
773	int *valp;
774{
775	int error = 0;
776
777	if (oldp && *oldlenp < sizeof(int))
778		return (ENOMEM);
779	if (newp && newlen != sizeof(int))
780		return (EINVAL);
781	*oldlenp = sizeof(int);
782	if (oldp)
783		error = copyout(valp, oldp, sizeof(int));
784	if (error == 0 && newp)
785		error = copyin(newp, valp, sizeof(int));
786	return (error);
787}
788
789/*
790 * As above, but read-only.
791 */
792int
793sysctl_rdint(oldp, oldlenp, newp, val)
794	void *oldp;
795	size_t *oldlenp;
796	void *newp;
797	int val;
798{
799	int error = 0;
800
801	if (oldp && *oldlenp < sizeof(int))
802		return (ENOMEM);
803	if (newp)
804		return (EPERM);
805	*oldlenp = sizeof(int);
806	if (oldp)
807		error = copyout((caddr_t)&val, oldp, sizeof(int));
808	return (error);
809}
810
811/*
812 * Validate parameters and get old / set new parameters
813 * for a string-valued sysctl function.
814 */
815int
816sysctl_string(oldp, oldlenp, newp, newlen, str, maxlen)
817	void *oldp;
818	size_t *oldlenp;
819	void *newp;
820	size_t newlen;
821	char *str;
822	int maxlen;
823{
824	int len, error = 0, rval = 0;
825
826	len = strlen(str) + 1;
827	if (oldp && *oldlenp < len) {
828		len = *oldlenp;
829		rval = ENOMEM;
830	}
831	if (newp && newlen >= maxlen)
832		return (EINVAL);
833	if (oldp) {
834		*oldlenp = len;
835		error = copyout(str, oldp, len);
836		if (error)
837			rval = error;
838	}
839	if ((error == 0 || error == ENOMEM) && newp) {
840		error = copyin(newp, str, newlen);
841		if (error)
842			rval = error;
843		str[newlen] = 0;
844	}
845	return (rval);
846}
847
848/*
849 * As above, but read-only.
850 */
851int
852sysctl_rdstring(oldp, oldlenp, newp, str)
853	void *oldp;
854	size_t *oldlenp;
855	void *newp;
856	char *str;
857{
858	int len, error = 0, rval = 0;
859
860	len = strlen(str) + 1;
861	if (oldp && *oldlenp < len) {
862		len = *oldlenp;
863		rval = ENOMEM;
864	}
865	if (newp)
866		return (EPERM);
867	*oldlenp = len;
868	if (oldp)
869		error = copyout(str, oldp, len);
870		if (error)
871			rval = error;
872	return (rval);
873}
874
875/*
876 * Validate parameters and get old / set new parameters
877 * for a structure oriented sysctl function.
878 */
879int
880sysctl_struct(oldp, oldlenp, newp, newlen, sp, len)
881	void *oldp;
882	size_t *oldlenp;
883	void *newp;
884	size_t newlen;
885	void *sp;
886	int len;
887{
888	int error = 0;
889
890	if (oldp && *oldlenp < len)
891		return (ENOMEM);
892	if (newp && newlen > len)
893		return (EINVAL);
894	if (oldp) {
895		*oldlenp = len;
896		error = copyout(sp, oldp, len);
897	}
898	if (error == 0 && newp)
899		error = copyin(newp, sp, len);
900	return (error);
901}
902
903/*
904 * Validate parameters and get old parameters
905 * for a structure oriented sysctl function.
906 */
907int
908sysctl_rdstruct(oldp, oldlenp, newp, sp, len)
909	void *oldp;
910	size_t *oldlenp;
911	void *newp, *sp;
912	int len;
913{
914	int error = 0;
915
916	if (oldp && *oldlenp < len)
917		return (ENOMEM);
918	if (newp)
919		return (EPERM);
920	*oldlenp = len;
921	if (oldp)
922		error = copyout(sp, oldp, len);
923	return (error);
924}
925
926/*
927 * Get file structures.
928 */
929int
930sysctl_file(where, sizep)
931	char *where;
932	size_t *sizep;
933{
934	int buflen, error;
935	struct file *fp;
936	char *start = where;
937
938	buflen = *sizep;
939	if (where == NULL) {
940		/*
941		 * overestimate by 10 files
942		 */
943		*sizep = sizeof(filehead) + (nfiles + 10) * sizeof(struct file);
944		return (0);
945	}
946
947	/*
948	 * first copyout filehead
949	 */
950	if (buflen < sizeof(filehead)) {
951		*sizep = 0;
952		return (0);
953	}
954	error = copyout((caddr_t)&filehead, where, sizeof(filehead));
955	if (error)
956		return (error);
957	buflen -= sizeof(filehead);
958	where += sizeof(filehead);
959
960	/*
961	 * followed by an array of file structures
962	 */
963	for (fp = filehead; fp != NULL; fp = fp->f_filef) {
964		if (buflen < sizeof(struct file)) {
965			*sizep = where - start;
966			return (ENOMEM);
967		}
968		error = copyout((caddr_t)fp, where, sizeof (struct file));
969		if (error)
970			return (error);
971		buflen -= sizeof(struct file);
972		where += sizeof(struct file);
973	}
974	*sizep = where - start;
975	return (0);
976}
977
978/*
979 * try over estimating by 5 procs
980 */
981#define KERN_PROCSLOP	(5 * sizeof (struct kinfo_proc))
982
983int
984sysctl_doproc(name, namelen, where, sizep)
985	int *name;
986	u_int namelen;
987	char *where;
988	size_t *sizep;
989{
990	register struct proc *p;
991	register struct kinfo_proc *dp = (struct kinfo_proc *)where;
992	register int needed = 0;
993	int buflen = where != NULL ? *sizep : 0;
994	int doingzomb;
995	struct eproc eproc;
996	int error = 0;
997
998	if (namelen != 2 && !(namelen == 1 && name[0] == KERN_PROC_ALL))
999		return (EINVAL);
1000	p = (struct proc *)allproc;
1001	doingzomb = 0;
1002again:
1003	for (; p != NULL; p = p->p_next) {
1004		/*
1005		 * Skip embryonic processes.
1006		 */
1007		if (p->p_stat == SIDL)
1008			continue;
1009		/*
1010		 * TODO - make more efficient (see notes below).
1011		 * do by session.
1012		 */
1013		switch (name[0]) {
1014
1015		case KERN_PROC_PID:
1016			/* could do this with just a lookup */
1017			if (p->p_pid != (pid_t)name[1])
1018				continue;
1019			break;
1020
1021		case KERN_PROC_PGRP:
1022			/* could do this by traversing pgrp */
1023			if (p->p_pgrp == NULL || p->p_pgrp->pg_id != (pid_t)name[1])
1024				continue;
1025			break;
1026
1027		case KERN_PROC_TTY:
1028			if ((p->p_flag & P_CONTROLT) == 0 ||
1029			    p->p_session == NULL ||
1030			    p->p_session->s_ttyp == NULL ||
1031			    p->p_session->s_ttyp->t_dev != (dev_t)name[1])
1032				continue;
1033			break;
1034
1035		case KERN_PROC_UID:
1036			if (p->p_ucred == NULL || p->p_ucred->cr_uid != (uid_t)name[1])
1037				continue;
1038			break;
1039
1040		case KERN_PROC_RUID:
1041			if (p->p_ucred == NULL || p->p_cred->p_ruid != (uid_t)name[1])
1042				continue;
1043			break;
1044		}
1045		if (buflen >= sizeof(struct kinfo_proc)) {
1046			fill_eproc(p, &eproc);
1047			error = copyout((caddr_t)p, &dp->kp_proc,
1048			    sizeof(struct proc));
1049			if (error)
1050				return (error);
1051			error = copyout((caddr_t)&eproc, &dp->kp_eproc,
1052			    sizeof(eproc));
1053			if (error)
1054				return (error);
1055			dp++;
1056			buflen -= sizeof(struct kinfo_proc);
1057		}
1058		needed += sizeof(struct kinfo_proc);
1059	}
1060	if (doingzomb == 0) {
1061		p = zombproc;
1062		doingzomb++;
1063		goto again;
1064	}
1065	if (where != NULL) {
1066		*sizep = (caddr_t)dp - where;
1067		if (needed > *sizep)
1068			return (ENOMEM);
1069	} else {
1070		needed += KERN_PROCSLOP;
1071		*sizep = needed;
1072	}
1073	return (0);
1074}
1075
1076/*
1077 * Fill in an eproc structure for the specified process.
1078 */
1079void
1080fill_eproc(p, ep)
1081	register struct proc *p;
1082	register struct eproc *ep;
1083{
1084	register struct tty *tp;
1085
1086	bzero(ep, sizeof(*ep));
1087
1088	ep->e_paddr = p;
1089	if (p->p_cred) {
1090		ep->e_pcred = *p->p_cred;
1091		if (p->p_ucred)
1092			ep->e_ucred = *p->p_ucred;
1093	}
1094	if (p->p_stat != SIDL && p->p_stat != SZOMB && p->p_vmspace != NULL) {
1095		register struct vmspace *vm = p->p_vmspace;
1096
1097#ifdef pmap_resident_count
1098		ep->e_vm.vm_rssize = pmap_resident_count(&vm->vm_pmap); /*XXX*/
1099#else
1100		ep->e_vm.vm_rssize = vm->vm_rssize;
1101#endif
1102		ep->e_vm.vm_tsize = vm->vm_tsize;
1103		ep->e_vm.vm_dsize = vm->vm_dsize;
1104		ep->e_vm.vm_ssize = vm->vm_ssize;
1105#ifndef sparc
1106		ep->e_vm.vm_pmap = vm->vm_pmap;
1107#endif
1108	}
1109	if (p->p_pptr)
1110		ep->e_ppid = p->p_pptr->p_pid;
1111	if (p->p_pgrp) {
1112		ep->e_sess = p->p_pgrp->pg_session;
1113		ep->e_pgid = p->p_pgrp->pg_id;
1114		ep->e_jobc = p->p_pgrp->pg_jobc;
1115	}
1116	if ((p->p_flag & P_CONTROLT) &&
1117	    (ep->e_sess != NULL) &&
1118	    ((tp = ep->e_sess->s_ttyp) != NULL)) {
1119		ep->e_tdev = tp->t_dev;
1120		ep->e_tpgid = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID;
1121		ep->e_tsess = tp->t_session;
1122	} else
1123		ep->e_tdev = NODEV;
1124	if (ep->e_sess && ep->e_sess->s_ttyvp)
1125		ep->e_flag = EPROC_CTTY;
1126	if (SESS_LEADER(p))
1127		ep->e_flag |= EPROC_SLEADER;
1128	if (p->p_wmesg) {
1129		strncpy(ep->e_wmesg, p->p_wmesg, WMESGLEN);
1130		ep->e_wmesg[WMESGLEN] = 0;
1131	}
1132}
1133
1134#ifdef COMPAT_43
1135#include <sys/socket.h>
1136#define	KINFO_PROC		(0<<8)
1137#define	KINFO_RT		(1<<8)
1138#define	KINFO_VNODE		(2<<8)
1139#define	KINFO_FILE		(3<<8)
1140#define	KINFO_METER		(4<<8)
1141#define	KINFO_LOADAVG		(5<<8)
1142#define	KINFO_CLOCKRATE		(6<<8)
1143
1144/* Non-standard BSDI extension - only present on their 4.3 net-2 releases */
1145#define	KINFO_BSDI_SYSINFO	(101<<8)
1146
1147/*
1148 * XXX this is bloat, but I hope it's better here than on the potentially
1149 * limited kernel stack...  -Peter
1150 */
1151
1152struct {
1153	int	bsdi_machine;		/* "i386" on BSD/386 */
1154/*      ^^^ this is an offset to the string, relative to the struct start */
1155	char	*pad0;
1156	long	pad1;
1157	long	pad2;
1158	long	pad3;
1159	u_long	pad4;
1160	u_long	pad5;
1161	u_long	pad6;
1162
1163	int	bsdi_ostype;		/* "BSD/386" on BSD/386 */
1164	int	bsdi_osrelease;		/* "1.1" on BSD/386 */
1165	long	pad7;
1166	long	pad8;
1167	char	*pad9;
1168
1169	long	pad10;
1170	long	pad11;
1171	int	pad12;
1172	long	pad13;
1173	quad_t	pad14;
1174	long	pad15;
1175
1176	struct	timeval pad16;
1177	/* we dont set this, because BSDI's uname used gethostname() instead */
1178	int	bsdi_hostname;		/* hostname on BSD/386 */
1179
1180	/* the actual string data is appended here */
1181
1182} bsdi_si;
1183/*
1184 * this data is appended to the end of the bsdi_si structure during copyout.
1185 * The "char *" offsets are relative to the base of the bsdi_si struct.
1186 * This contains "FreeBSD\02.0-BUILT-nnnnnn\0i386\0", and these strings
1187 * should not exceed the length of the buffer here... (or else!! :-)
1188 */
1189char bsdi_strings[80];	/* It had better be less than this! */
1190
1191#ifndef _SYS_SYSPROTO_H_
1192struct getkerninfo_args {
1193	int	op;
1194	char	*where;
1195	int	*size;
1196	int	arg;
1197};
1198#endif
1199
1200int
1201ogetkerninfo(p, uap, retval)
1202	struct proc *p;
1203	register struct getkerninfo_args *uap;
1204	int *retval;
1205{
1206	int error, name[6];
1207	u_int size;
1208
1209	switch (uap->op & 0xff00) {
1210
1211	case KINFO_RT:
1212		name[0] = CTL_NET;
1213		name[1] = PF_ROUTE;
1214		name[2] = 0;
1215		name[3] = (uap->op & 0xff0000) >> 16;
1216		name[4] = uap->op & 0xff;
1217		name[5] = uap->arg;
1218		error = userland_sysctl(p, name, 6, uap->where, uap->size,
1219			0, 0, 0, 0);
1220		break;
1221
1222	case KINFO_VNODE:
1223		name[0] = CTL_KERN;
1224		name[1] = KERN_VNODE;
1225		error = userland_sysctl(p, name, 2, uap->where, uap->size,
1226			0, 0, 0, 0);
1227		break;
1228
1229	case KINFO_PROC:
1230		name[0] = CTL_KERN;
1231		name[1] = KERN_PROC;
1232		name[2] = uap->op & 0xff;
1233		name[3] = uap->arg;
1234		error = userland_sysctl(p, name, 4, uap->where, uap->size,
1235			0, 0, 0, 0);
1236		break;
1237
1238	case KINFO_FILE:
1239		name[0] = CTL_KERN;
1240		name[1] = KERN_FILE;
1241		error = userland_sysctl(p, name, 2, uap->where, uap->size,
1242			0, 0, 0, 0);
1243		break;
1244
1245	case KINFO_METER:
1246		name[0] = CTL_VM;
1247		name[1] = VM_METER;
1248		error = userland_sysctl(p, name, 2, uap->where, uap->size,
1249			0, 0, 0, 0);
1250		break;
1251
1252	case KINFO_LOADAVG:
1253		name[0] = CTL_VM;
1254		name[1] = VM_LOADAVG;
1255		error = userland_sysctl(p, name, 2, uap->where, uap->size,
1256			0, 0, 0, 0);
1257		break;
1258
1259	case KINFO_CLOCKRATE:
1260		name[0] = CTL_KERN;
1261		name[1] = KERN_CLOCKRATE;
1262		error = userland_sysctl(p, name, 2, uap->where, uap->size,
1263			0, 0, 0, 0);
1264		break;
1265
1266	case KINFO_BSDI_SYSINFO: {
1267		/*
1268		 * this is pretty crude, but it's just enough for uname()
1269		 * from BSDI's 1.x libc to work.
1270		 *
1271		 * In particular, it doesn't return the same results when
1272		 * the supplied buffer is too small.  BSDI's version apparently
1273		 * will return the amount copied, and set the *size to how
1274		 * much was needed.  The emulation framework here isn't capable
1275		 * of that, so we just set both to the amount copied.
1276		 * BSDI's 2.x product apparently fails with ENOMEM in this
1277		 * scenario.
1278		 */
1279
1280		u_int needed;
1281		u_int left;
1282		char *s;
1283
1284		bzero((char *)&bsdi_si, sizeof(bsdi_si));
1285		bzero(bsdi_strings, sizeof(bsdi_strings));
1286
1287		s = bsdi_strings;
1288
1289		bsdi_si.bsdi_ostype = (s - bsdi_strings) + sizeof(bsdi_si);
1290		strcpy(s, ostype);
1291		s += strlen(s) + 1;
1292
1293		bsdi_si.bsdi_osrelease = (s - bsdi_strings) + sizeof(bsdi_si);
1294		strcpy(s, osrelease);
1295		s += strlen(s) + 1;
1296
1297		bsdi_si.bsdi_machine = (s - bsdi_strings) + sizeof(bsdi_si);
1298		strcpy(s, machine);
1299		s += strlen(s) + 1;
1300
1301		needed = sizeof(bsdi_si) + (s - bsdi_strings);
1302
1303		if (uap->where == NULL) {
1304			/* process is asking how much buffer to supply.. */
1305			size = needed;
1306			error = 0;
1307			break;
1308		}
1309
1310
1311		/* if too much buffer supplied, trim it down */
1312		if (size > needed)
1313			size = needed;
1314
1315		/* how much of the buffer is remaining */
1316		left = size;
1317
1318		if ((error = copyout((char *)&bsdi_si, uap->where, left)) != 0)
1319			break;
1320
1321		/* is there any point in continuing? */
1322		if (left > sizeof(bsdi_si)) {
1323			left -= sizeof(bsdi_si);
1324			error = copyout(&bsdi_strings,
1325					uap->where + sizeof(bsdi_si), left);
1326		}
1327		break;
1328	}
1329
1330	default:
1331		return (EOPNOTSUPP);
1332	}
1333	if (error)
1334		return (error);
1335	*retval = size;
1336	if (uap->size)
1337		error = copyout((caddr_t)&size, (caddr_t)uap->size,
1338		    sizeof(size));
1339	return (error);
1340}
1341#endif /* COMPAT_43 */
1342