kern_sysctl.c revision 80338
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 * Quite extensively rewritten by Poul-Henning Kamp of the FreeBSD
9 * project, to make these variables more userfriendly.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 *    notice, this list of conditions and the following disclaimer in the
18 *    documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 *    must display the following acknowledgement:
21 *	This product includes software developed by the University of
22 *	California, Berkeley and its contributors.
23 * 4. Neither the name of the University nor the names of its contributors
24 *    may be used to endorse or promote products derived from this software
25 *    without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * SUCH DAMAGE.
38 *
39 *	@(#)kern_sysctl.c	8.4 (Berkeley) 4/14/94
40 * $FreeBSD: head/sys/kern/kern_sysctl.c 80338 2001-07-25 17:13:58Z roam $
41 */
42
43#include "opt_compat.h"
44
45#include <sys/param.h>
46#include <sys/systm.h>
47#include <sys/kernel.h>
48#include <sys/sysctl.h>
49#include <sys/malloc.h>
50#include <sys/proc.h>
51#include <sys/sysproto.h>
52#include <vm/vm.h>
53#include <vm/vm_extern.h>
54
55static MALLOC_DEFINE(M_SYSCTL, "sysctl", "sysctl internal magic");
56static MALLOC_DEFINE(M_SYSCTLOID, "sysctloid", "sysctl dynamic oids");
57
58/*
59 * Locking and stats
60 */
61static struct sysctl_lock {
62	int	sl_lock;
63	int	sl_want;
64	int	sl_locked;
65} memlock;
66
67static int sysctl_root(SYSCTL_HANDLER_ARGS);
68
69struct sysctl_oid_list sysctl__children; /* root list */
70
71static struct sysctl_oid *
72sysctl_find_oidname(const char *name, struct sysctl_oid_list *list)
73{
74	struct sysctl_oid *oidp;
75
76	SLIST_FOREACH(oidp, list, oid_link) {
77		if (strcmp(oidp->oid_name, name) == 0) {
78			return (oidp);
79		}
80	}
81	return (NULL);
82}
83
84/*
85 * Initialization of the MIB tree.
86 *
87 * Order by number in each list.
88 */
89
90void
91sysctl_register_oid(struct sysctl_oid *oidp)
92{
93	struct sysctl_oid_list *parent = oidp->oid_parent;
94	struct sysctl_oid *p;
95	struct sysctl_oid *q;
96
97	/*
98	 * First check if another oid with the same name already
99	 * exists in the parent's list.
100	 */
101	p = sysctl_find_oidname(oidp->oid_name, parent);
102	if (p != NULL) {
103		if ((p->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
104			p->oid_refcnt++;
105			return;
106		} else {
107			printf("can't re-use a leaf (%s)!\n", p->oid_name);
108			return;
109		}
110	}
111	/*
112	 * If this oid has a number OID_AUTO, give it a number which
113	 * is greater than any current oid.  Make sure it is at least
114	 * 100 to leave space for pre-assigned oid numbers.
115	 */
116	if (oidp->oid_number == OID_AUTO) {
117		static int newoid = 100;
118
119		oidp->oid_number = newoid++;
120		if (newoid == 0x7fffffff)
121			panic("out of oids");
122	}
123
124	/*
125	 * Insert the oid into the parent's list in order.
126	 */
127	q = NULL;
128	SLIST_FOREACH(p, parent, oid_link) {
129		if (oidp->oid_number < p->oid_number)
130			break;
131		q = p;
132	}
133	if (q)
134		SLIST_INSERT_AFTER(q, oidp, oid_link);
135	else
136		SLIST_INSERT_HEAD(parent, oidp, oid_link);
137}
138
139void
140sysctl_unregister_oid(struct sysctl_oid *oidp)
141{
142	SLIST_REMOVE(oidp->oid_parent, oidp, sysctl_oid, oid_link);
143}
144
145/* Initialize a new context to keep track of dynamically added sysctls. */
146int
147sysctl_ctx_init(struct sysctl_ctx_list *c)
148{
149
150	if (c == NULL) {
151		return (EINVAL);
152	}
153	TAILQ_INIT(c);
154	return (0);
155}
156
157/* Free the context, and destroy all dynamic oids registered in this context */
158int
159sysctl_ctx_free(struct sysctl_ctx_list *clist)
160{
161	struct sysctl_ctx_entry *e, *e1;
162	int error;
163
164	error = 0;
165	/*
166	 * First perform a "dry run" to check if it's ok to remove oids.
167	 * XXX FIXME
168	 * XXX This algorithm is a hack. But I don't know any
169	 * XXX better solution for now...
170	 */
171	TAILQ_FOREACH(e, clist, link) {
172		error = sysctl_remove_oid(e->entry, 0, 0);
173		if (error)
174			break;
175	}
176	/*
177	 * Restore deregistered entries, either from the end,
178	 * or from the place where error occured.
179	 * e contains the entry that was not unregistered
180	 */
181	if (error)
182		e1 = TAILQ_PREV(e, sysctl_ctx_list, link);
183	else
184		e1 = TAILQ_LAST(clist, sysctl_ctx_list);
185	while (e1 != NULL) {
186		sysctl_register_oid(e1->entry);
187		e1 = TAILQ_PREV(e1, sysctl_ctx_list, link);
188	}
189	if (error)
190		return(EBUSY);
191	/* Now really delete the entries */
192	e = TAILQ_FIRST(clist);
193	while (e != NULL) {
194		e1 = TAILQ_NEXT(e, link);
195		error = sysctl_remove_oid(e->entry, 1, 0);
196		if (error)
197			panic("sysctl_remove_oid: corrupt tree, entry: %s",
198			    e->entry->oid_name);
199		free(e, M_SYSCTLOID);
200		e = e1;
201	}
202	return (error);
203}
204
205/* Add an entry to the context */
206struct sysctl_ctx_entry *
207sysctl_ctx_entry_add(struct sysctl_ctx_list *clist, struct sysctl_oid *oidp)
208{
209	struct sysctl_ctx_entry *e;
210
211	if (clist == NULL || oidp == NULL)
212		return(NULL);
213	e = malloc(sizeof(struct sysctl_ctx_entry), M_SYSCTLOID, M_WAITOK);
214	e->entry = oidp;
215	TAILQ_INSERT_HEAD(clist, e, link);
216	return (e);
217}
218
219/* Find an entry in the context */
220struct sysctl_ctx_entry *
221sysctl_ctx_entry_find(struct sysctl_ctx_list *clist, struct sysctl_oid *oidp)
222{
223	struct sysctl_ctx_entry *e;
224
225	if (clist == NULL || oidp == NULL)
226		return(NULL);
227	TAILQ_FOREACH(e, clist, link) {
228		if(e->entry == oidp)
229			return(e);
230	}
231	return (e);
232}
233
234/*
235 * Delete an entry from the context.
236 * NOTE: this function doesn't free oidp! You have to remove it
237 * with sysctl_remove_oid().
238 */
239int
240sysctl_ctx_entry_del(struct sysctl_ctx_list *clist, struct sysctl_oid *oidp)
241{
242	struct sysctl_ctx_entry *e;
243
244	if (clist == NULL || oidp == NULL)
245		return (EINVAL);
246	e = sysctl_ctx_entry_find(clist, oidp);
247	if (e != NULL) {
248		TAILQ_REMOVE(clist, e, link);
249		free(e, M_SYSCTLOID);
250		return (0);
251	} else
252		return (ENOENT);
253}
254
255/*
256 * Remove dynamically created sysctl trees.
257 * oidp - top of the tree to be removed
258 * del - if 0 - just deregister, otherwise free up entries as well
259 * recurse - if != 0 traverse the subtree to be deleted
260 */
261int
262sysctl_remove_oid(struct sysctl_oid *oidp, int del, int recurse)
263{
264	struct sysctl_oid *p;
265	int error;
266
267	if (oidp == NULL)
268		return(EINVAL);
269	if ((oidp->oid_kind & CTLFLAG_DYN) == 0) {
270		printf("can't remove non-dynamic nodes!\n");
271		return (EINVAL);
272	}
273	/*
274	 * WARNING: normal method to do this should be through
275	 * sysctl_ctx_free(). Use recursing as the last resort
276	 * method to purge your sysctl tree of leftovers...
277	 * However, if some other code still references these nodes,
278	 * it will panic.
279	 */
280	if ((oidp->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
281		if (oidp->oid_refcnt == 1) {
282			SLIST_FOREACH(p, SYSCTL_CHILDREN(oidp), oid_link) {
283				if (!recurse)
284					return (ENOTEMPTY);
285				error = sysctl_remove_oid(p, del, recurse);
286				if (error)
287					return (error);
288			}
289			if (del)
290				free(SYSCTL_CHILDREN(oidp), M_SYSCTLOID);
291		}
292	}
293	if (oidp->oid_refcnt > 1 ) {
294		oidp->oid_refcnt--;
295	} else {
296		if (oidp->oid_refcnt == 0) {
297			printf("Warning: bad oid_refcnt=%u (%s)!\n",
298				oidp->oid_refcnt, oidp->oid_name);
299			return (EINVAL);
300		}
301		sysctl_unregister_oid(oidp);
302		if (del) {
303			free((void *)(uintptr_t)(const void *)oidp->oid_name,
304			     M_SYSCTLOID);
305			free(oidp, M_SYSCTLOID);
306		}
307	}
308	return (0);
309}
310
311/*
312 * Create new sysctls at run time.
313 * clist may point to a valid context initialized with sysctl_ctx_init().
314 */
315struct sysctl_oid *
316sysctl_add_oid(struct sysctl_ctx_list *clist, struct sysctl_oid_list *parent,
317	int number, const char *name, int kind, void *arg1, int arg2,
318	int (*handler)(SYSCTL_HANDLER_ARGS), const char *fmt, const char *descr)
319{
320	struct sysctl_oid *oidp;
321	ssize_t len;
322	char *newname;
323
324	/* You have to hook up somewhere.. */
325	if (parent == NULL)
326		return(NULL);
327	/* Check if the node already exists, otherwise create it */
328	oidp = sysctl_find_oidname(name, parent);
329	if (oidp != NULL) {
330		if ((oidp->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
331			oidp->oid_refcnt++;
332			/* Update the context */
333			if (clist != NULL)
334				sysctl_ctx_entry_add(clist, oidp);
335			return (oidp);
336		} else {
337			printf("can't re-use a leaf (%s)!\n", name);
338			return (NULL);
339		}
340	}
341	oidp = malloc(sizeof(struct sysctl_oid), M_SYSCTLOID, M_WAITOK|M_ZERO);
342	oidp->oid_parent = parent;
343	SLIST_NEXT(oidp, oid_link) = NULL;
344	oidp->oid_number = number;
345	oidp->oid_refcnt = 1;
346	len = strlen(name);
347	newname = malloc(len + 1, M_SYSCTLOID, M_WAITOK);
348	bcopy(name, newname, len + 1);
349	newname[len] = '\0';
350	oidp->oid_name = newname;
351	oidp->oid_handler = handler;
352	oidp->oid_kind = CTLFLAG_DYN | kind;
353	if ((kind & CTLTYPE) == CTLTYPE_NODE) {
354		/* Allocate space for children */
355		SYSCTL_CHILDREN(oidp) = malloc(sizeof(struct sysctl_oid_list),
356		    M_SYSCTLOID, M_WAITOK);
357		SLIST_INIT(SYSCTL_CHILDREN(oidp));
358	} else {
359		oidp->oid_arg1 = arg1;
360		oidp->oid_arg2 = arg2;
361	}
362	oidp->oid_fmt = fmt;
363	/* Update the context, if used */
364	if (clist != NULL)
365		sysctl_ctx_entry_add(clist, oidp);
366	/* Register this oid */
367	sysctl_register_oid(oidp);
368	return (oidp);
369}
370
371/*
372 * Register the kernel's oids on startup.
373 */
374SET_DECLARE(sysctl_set, struct sysctl_oid);
375
376static void
377sysctl_register_all(void *arg)
378{
379	struct sysctl_oid **oidp;
380
381	SET_FOREACH(oidp, sysctl_set)
382		sysctl_register_oid(*oidp);
383}
384SYSINIT(sysctl, SI_SUB_KMEM, SI_ORDER_ANY, sysctl_register_all, 0);
385
386/*
387 * "Staff-functions"
388 *
389 * These functions implement a presently undocumented interface
390 * used by the sysctl program to walk the tree, and get the type
391 * so it can print the value.
392 * This interface is under work and consideration, and should probably
393 * be killed with a big axe by the first person who can find the time.
394 * (be aware though, that the proper interface isn't as obvious as it
395 * may seem, there are various conflicting requirements.
396 *
397 * {0,0}	printf the entire MIB-tree.
398 * {0,1,...}	return the name of the "..." OID.
399 * {0,2,...}	return the next OID.
400 * {0,3}	return the OID of the name in "new"
401 * {0,4,...}	return the kind & format info for the "..." OID.
402 */
403
404static void
405sysctl_sysctl_debug_dump_node(struct sysctl_oid_list *l, int i)
406{
407	int k;
408	struct sysctl_oid *oidp;
409
410	SLIST_FOREACH(oidp, l, oid_link) {
411
412		for (k=0; k<i; k++)
413			printf(" ");
414
415		printf("%d %s ", oidp->oid_number, oidp->oid_name);
416
417		printf("%c%c",
418			oidp->oid_kind & CTLFLAG_RD ? 'R':' ',
419			oidp->oid_kind & CTLFLAG_WR ? 'W':' ');
420
421		if (oidp->oid_handler)
422			printf(" *Handler");
423
424		switch (oidp->oid_kind & CTLTYPE) {
425			case CTLTYPE_NODE:
426				printf(" Node\n");
427				if (!oidp->oid_handler) {
428					sysctl_sysctl_debug_dump_node(
429						oidp->oid_arg1, i+2);
430				}
431				break;
432			case CTLTYPE_INT:    printf(" Int\n"); break;
433			case CTLTYPE_STRING: printf(" String\n"); break;
434			case CTLTYPE_QUAD:   printf(" Quad\n"); break;
435			case CTLTYPE_OPAQUE: printf(" Opaque/struct\n"); break;
436			default:	     printf("\n");
437		}
438
439	}
440}
441
442static int
443sysctl_sysctl_debug(SYSCTL_HANDLER_ARGS)
444{
445	sysctl_sysctl_debug_dump_node(&sysctl__children, 0);
446	return ENOENT;
447}
448
449SYSCTL_PROC(_sysctl, 0, debug, CTLTYPE_STRING|CTLFLAG_RD,
450	0, 0, sysctl_sysctl_debug, "-", "");
451
452static int
453sysctl_sysctl_name(SYSCTL_HANDLER_ARGS)
454{
455	int *name = (int *) arg1;
456	u_int namelen = arg2;
457	int error = 0;
458	struct sysctl_oid *oid;
459	struct sysctl_oid_list *lsp = &sysctl__children, *lsp2;
460	char buf[10];
461
462	while (namelen) {
463		if (!lsp) {
464			snprintf(buf,sizeof(buf),"%d",*name);
465			if (req->oldidx)
466				error = SYSCTL_OUT(req, ".", 1);
467			if (!error)
468				error = SYSCTL_OUT(req, buf, strlen(buf));
469			if (error)
470				return (error);
471			namelen--;
472			name++;
473			continue;
474		}
475		lsp2 = 0;
476		SLIST_FOREACH(oid, lsp, oid_link) {
477			if (oid->oid_number != *name)
478				continue;
479
480			if (req->oldidx)
481				error = SYSCTL_OUT(req, ".", 1);
482			if (!error)
483				error = SYSCTL_OUT(req, oid->oid_name,
484					strlen(oid->oid_name));
485			if (error)
486				return (error);
487
488			namelen--;
489			name++;
490
491			if ((oid->oid_kind & CTLTYPE) != CTLTYPE_NODE)
492				break;
493
494			if (oid->oid_handler)
495				break;
496
497			lsp2 = (struct sysctl_oid_list *)oid->oid_arg1;
498			break;
499		}
500		lsp = lsp2;
501	}
502	return (SYSCTL_OUT(req, "", 1));
503}
504
505SYSCTL_NODE(_sysctl, 1, name, CTLFLAG_RD, sysctl_sysctl_name, "");
506
507static int
508sysctl_sysctl_next_ls(struct sysctl_oid_list *lsp, int *name, u_int namelen,
509	int *next, int *len, int level, struct sysctl_oid **oidpp)
510{
511	struct sysctl_oid *oidp;
512
513	*len = level;
514	SLIST_FOREACH(oidp, lsp, oid_link) {
515		*next = oidp->oid_number;
516		*oidpp = oidp;
517
518		if (!namelen) {
519			if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE)
520				return 0;
521			if (oidp->oid_handler)
522				/* We really should call the handler here...*/
523				return 0;
524			lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
525			if (!sysctl_sysctl_next_ls(lsp, 0, 0, next+1,
526				len, level+1, oidpp))
527				return 0;
528			goto next;
529		}
530
531		if (oidp->oid_number < *name)
532			continue;
533
534		if (oidp->oid_number > *name) {
535			if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE)
536				return 0;
537			if (oidp->oid_handler)
538				return 0;
539			lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
540			if (!sysctl_sysctl_next_ls(lsp, name+1, namelen-1,
541				next+1, len, level+1, oidpp))
542				return (0);
543			goto next;
544		}
545		if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE)
546			continue;
547
548		if (oidp->oid_handler)
549			continue;
550
551		lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
552		if (!sysctl_sysctl_next_ls(lsp, name+1, namelen-1, next+1,
553			len, level+1, oidpp))
554			return (0);
555	next:
556		namelen = 1;
557		*len = level;
558	}
559	return 1;
560}
561
562static int
563sysctl_sysctl_next(SYSCTL_HANDLER_ARGS)
564{
565	int *name = (int *) arg1;
566	u_int namelen = arg2;
567	int i, j, error;
568	struct sysctl_oid *oid;
569	struct sysctl_oid_list *lsp = &sysctl__children;
570	int newoid[CTL_MAXNAME];
571
572	i = sysctl_sysctl_next_ls(lsp, name, namelen, newoid, &j, 1, &oid);
573	if (i)
574		return ENOENT;
575	error = SYSCTL_OUT(req, newoid, j * sizeof (int));
576	return (error);
577}
578
579SYSCTL_NODE(_sysctl, 2, next, CTLFLAG_RD, sysctl_sysctl_next, "");
580
581static int
582name2oid (char *name, int *oid, int *len, struct sysctl_oid **oidpp)
583{
584	int i;
585	struct sysctl_oid *oidp;
586	struct sysctl_oid_list *lsp = &sysctl__children;
587	char *p;
588
589	if (!*name)
590		return ENOENT;
591
592	p = name + strlen(name) - 1 ;
593	if (*p == '.')
594		*p = '\0';
595
596	*len = 0;
597
598	for (p = name; *p && *p != '.'; p++)
599		;
600	i = *p;
601	if (i == '.')
602		*p = '\0';
603
604	oidp = SLIST_FIRST(lsp);
605
606	while (oidp && *len < CTL_MAXNAME) {
607		if (strcmp(name, oidp->oid_name)) {
608			oidp = SLIST_NEXT(oidp, oid_link);
609			continue;
610		}
611		*oid++ = oidp->oid_number;
612		(*len)++;
613
614		if (!i) {
615			if (oidpp)
616				*oidpp = oidp;
617			return (0);
618		}
619
620		if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE)
621			break;
622
623		if (oidp->oid_handler)
624			break;
625
626		lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
627		oidp = SLIST_FIRST(lsp);
628		name = p+1;
629		for (p = name; *p && *p != '.'; p++)
630				;
631		i = *p;
632		if (i == '.')
633			*p = '\0';
634	}
635	return ENOENT;
636}
637
638static int
639sysctl_sysctl_name2oid(SYSCTL_HANDLER_ARGS)
640{
641	char *p;
642	int error, oid[CTL_MAXNAME], len;
643	struct sysctl_oid *op = 0;
644
645	if (!req->newlen)
646		return ENOENT;
647	if (req->newlen >= MAXPATHLEN)	/* XXX arbitrary, undocumented */
648		return (ENAMETOOLONG);
649
650	p = malloc(req->newlen+1, M_SYSCTL, M_WAITOK);
651
652	error = SYSCTL_IN(req, p, req->newlen);
653	if (error) {
654		free(p, M_SYSCTL);
655		return (error);
656	}
657
658	p [req->newlen] = '\0';
659
660	error = name2oid(p, oid, &len, &op);
661
662	free(p, M_SYSCTL);
663
664	if (error)
665		return (error);
666
667	error = SYSCTL_OUT(req, oid, len * sizeof *oid);
668	return (error);
669}
670
671SYSCTL_PROC(_sysctl, 3, name2oid, CTLFLAG_RW|CTLFLAG_ANYBODY, 0, 0,
672	sysctl_sysctl_name2oid, "I", "");
673
674static int
675sysctl_sysctl_oidfmt(SYSCTL_HANDLER_ARGS)
676{
677	struct sysctl_oid *oid;
678	int error;
679
680	error = sysctl_find_oid(arg1, arg2, &oid, NULL, req);
681	if (error)
682		return (error);
683
684	if (!oid->oid_fmt)
685		return (ENOENT);
686	error = SYSCTL_OUT(req, &oid->oid_kind, sizeof(oid->oid_kind));
687	if (error)
688		return (error);
689	error = SYSCTL_OUT(req, oid->oid_fmt, strlen(oid->oid_fmt) + 1);
690	return (error);
691}
692
693
694SYSCTL_NODE(_sysctl, 4, oidfmt, CTLFLAG_RD, sysctl_sysctl_oidfmt, "");
695
696/*
697 * Default "handler" functions.
698 */
699
700/*
701 * Handle an int, signed or unsigned.
702 * Two cases:
703 *     a variable:  point arg1 at it.
704 *     a constant:  pass it in arg2.
705 */
706
707int
708sysctl_handle_int(SYSCTL_HANDLER_ARGS)
709{
710	int error = 0;
711
712	if (arg1)
713		error = SYSCTL_OUT(req, arg1, sizeof(int));
714	else
715		error = SYSCTL_OUT(req, &arg2, sizeof(int));
716
717	if (error || !req->newptr)
718		return (error);
719
720	if (!arg1)
721		error = EPERM;
722	else
723		error = SYSCTL_IN(req, arg1, sizeof(int));
724	return (error);
725}
726
727/*
728 * Handle a long, signed or unsigned.  arg1 points to it.
729 */
730
731int
732sysctl_handle_long(SYSCTL_HANDLER_ARGS)
733{
734	int error = 0;
735
736	if (!arg1)
737		return (EINVAL);
738	error = SYSCTL_OUT(req, arg1, sizeof(long));
739
740	if (error || !req->newptr)
741		return (error);
742
743	error = SYSCTL_IN(req, arg1, sizeof(long));
744	return (error);
745}
746
747/*
748 * Handle our generic '\0' terminated 'C' string.
749 * Two cases:
750 * 	a variable string:  point arg1 at it, arg2 is max length.
751 * 	a constant string:  point arg1 at it, arg2 is zero.
752 */
753
754int
755sysctl_handle_string(SYSCTL_HANDLER_ARGS)
756{
757	int error=0;
758
759	error = SYSCTL_OUT(req, arg1, strlen((char *)arg1)+1);
760
761	if (error || !req->newptr)
762		return (error);
763
764	if ((req->newlen - req->newidx) >= arg2) {
765		error = EINVAL;
766	} else {
767		arg2 = (req->newlen - req->newidx);
768		error = SYSCTL_IN(req, arg1, arg2);
769		((char *)arg1)[arg2] = '\0';
770	}
771
772	return (error);
773}
774
775/*
776 * Handle any kind of opaque data.
777 * arg1 points to it, arg2 is the size.
778 */
779
780int
781sysctl_handle_opaque(SYSCTL_HANDLER_ARGS)
782{
783	int error;
784
785	error = SYSCTL_OUT(req, arg1, arg2);
786
787	if (error || !req->newptr)
788		return (error);
789
790	error = SYSCTL_IN(req, arg1, arg2);
791
792	return (error);
793}
794
795/*
796 * Transfer functions to/from kernel space.
797 * XXX: rather untested at this point
798 */
799static int
800sysctl_old_kernel(struct sysctl_req *req, const void *p, size_t l)
801{
802	size_t i = 0;
803
804	if (req->oldptr) {
805		i = l;
806		if (req->oldlen <= req->oldidx)
807			i = 0;
808		else
809			if (i > req->oldlen - req->oldidx)
810				i = req->oldlen - req->oldidx;
811		if (i > 0)
812			bcopy(p, (char *)req->oldptr + req->oldidx, i);
813	}
814	req->oldidx += l;
815	if (req->oldptr && i != l)
816		return (ENOMEM);
817	return (0);
818}
819
820static int
821sysctl_new_kernel(struct sysctl_req *req, void *p, size_t l)
822{
823	if (!req->newptr)
824		return 0;
825	if (req->newlen - req->newidx < l)
826		return (EINVAL);
827	bcopy((char *)req->newptr + req->newidx, p, l);
828	req->newidx += l;
829	return (0);
830}
831
832int
833kernel_sysctl(struct proc *p, int *name, u_int namelen, void *old,
834    size_t *oldlenp, void *new, size_t newlen, size_t *retval)
835{
836	int error = 0;
837	struct sysctl_req req;
838
839	bzero(&req, sizeof req);
840
841	req.p = p;
842
843	if (oldlenp) {
844		req.oldlen = *oldlenp;
845	}
846
847	if (old) {
848		req.oldptr= old;
849	}
850
851	if (new != NULL) {
852		req.newlen = newlen;
853		req.newptr = new;
854	}
855
856	req.oldfunc = sysctl_old_kernel;
857	req.newfunc = sysctl_new_kernel;
858	req.lock = 1;
859
860	/* XXX this should probably be done in a general way */
861	while (memlock.sl_lock) {
862		memlock.sl_want = 1;
863		(void) tsleep((caddr_t)&memlock, PRIBIO+1, "sysctl", 0);
864		memlock.sl_locked++;
865	}
866	memlock.sl_lock = 1;
867
868	error = sysctl_root(0, name, namelen, &req);
869
870	if (req.lock == 2)
871		vsunlock(req.oldptr, req.oldlen);
872
873	memlock.sl_lock = 0;
874
875	if (memlock.sl_want) {
876		memlock.sl_want = 0;
877		wakeup((caddr_t)&memlock);
878	}
879
880	if (error && error != ENOMEM)
881		return (error);
882
883	if (retval) {
884		if (req.oldptr && req.oldidx > req.oldlen)
885			*retval = req.oldlen;
886		else
887			*retval = req.oldidx;
888	}
889	return (error);
890}
891
892int
893kernel_sysctlbyname(struct proc *p, char *name, void *old, size_t *oldlenp,
894    void *new, size_t newlen, size_t *retval)
895{
896        int oid[CTL_MAXNAME];
897        size_t oidlen, plen;
898	int error;
899
900	oid[0] = 0;		/* sysctl internal magic */
901	oid[1] = 3;		/* name2oid */
902	oidlen = sizeof(oid);
903
904	error = kernel_sysctl(p, oid, 2, oid, &oidlen,
905	    (void *)name, strlen(name), &plen);
906	if (error)
907		return (error);
908
909	error = kernel_sysctl(p, oid, plen / sizeof(int), old, oldlenp,
910	    new, newlen, retval);
911	return (error);
912}
913
914/*
915 * Transfer function to/from user space.
916 */
917static int
918sysctl_old_user(struct sysctl_req *req, const void *p, size_t l)
919{
920	int error = 0;
921	size_t i = 0;
922
923	if (req->lock == 1 && req->oldptr) {
924		vslock(req->oldptr, req->oldlen);
925		req->lock = 2;
926	}
927	if (req->oldptr) {
928		i = l;
929		if (req->oldlen <= req->oldidx)
930			i = 0;
931		else
932			if (i > req->oldlen - req->oldidx)
933				i = req->oldlen - req->oldidx;
934		if (i > 0)
935			error = copyout(p, (char *)req->oldptr + req->oldidx,
936					i);
937	}
938	req->oldidx += l;
939	if (error)
940		return (error);
941	if (req->oldptr && i < l)
942		return (ENOMEM);
943	return (0);
944}
945
946static int
947sysctl_new_user(struct sysctl_req *req, void *p, size_t l)
948{
949	int error;
950
951	if (!req->newptr)
952		return 0;
953	if (req->newlen - req->newidx < l)
954		return (EINVAL);
955	error = copyin((char *)req->newptr + req->newidx, p, l);
956	req->newidx += l;
957	return (error);
958}
959
960int
961sysctl_find_oid(int *name, u_int namelen, struct sysctl_oid **noid,
962    int *nindx, struct sysctl_req *req)
963{
964	struct sysctl_oid *oid;
965	int indx;
966
967	oid = SLIST_FIRST(&sysctl__children);
968	indx = 0;
969	while (oid && indx < CTL_MAXNAME) {
970		if (oid->oid_number == name[indx]) {
971			indx++;
972			if (oid->oid_kind & CTLFLAG_NOLOCK)
973				req->lock = 0;
974			if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
975				if (oid->oid_handler != NULL ||
976				    indx == namelen) {
977					*noid = oid;
978					if (nindx != NULL)
979						*nindx = indx;
980					return (0);
981				}
982				oid = SLIST_FIRST(
983				    (struct sysctl_oid_list *)oid->oid_arg1);
984			} else if (indx == namelen) {
985				*noid = oid;
986				if (nindx != NULL)
987					*nindx = indx;
988				return (0);
989			} else {
990				return (ENOTDIR);
991			}
992		} else {
993			oid = SLIST_NEXT(oid, oid_link);
994		}
995	}
996	return (ENOENT);
997}
998
999/*
1000 * Traverse our tree, and find the right node, execute whatever it points
1001 * to, and return the resulting error code.
1002 */
1003
1004int
1005sysctl_root(SYSCTL_HANDLER_ARGS)
1006{
1007	struct sysctl_oid *oid;
1008	int error, indx;
1009
1010	error = sysctl_find_oid(arg1, arg2, &oid, &indx, req);
1011	if (error)
1012		return (error);
1013
1014	if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
1015		/*
1016		 * You can't call a sysctl when it's a node, but has
1017		 * no handler.  Inform the user that it's a node.
1018		 * The indx may or may not be the same as namelen.
1019		 */
1020		if (oid->oid_handler == NULL)
1021			return (EISDIR);
1022	}
1023
1024	/* If writing isn't allowed */
1025	if (req->newptr && (!(oid->oid_kind & CTLFLAG_WR) ||
1026	    ((oid->oid_kind & CTLFLAG_SECURE) && securelevel > 0)))
1027		return (EPERM);
1028
1029	/* Most likely only root can write */
1030	if (!(oid->oid_kind & CTLFLAG_ANYBODY) &&
1031	    req->newptr && req->p &&
1032	    (error = suser_xxx(0, req->p,
1033	    (oid->oid_kind & CTLFLAG_PRISON) ? PRISON_ROOT : 0)))
1034		return (error);
1035
1036	if (!oid->oid_handler)
1037		return EINVAL;
1038
1039	if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE)
1040		error = oid->oid_handler(oid, (int *)arg1 + indx, arg2 - indx,
1041		    req);
1042	else
1043		error = oid->oid_handler(oid, oid->oid_arg1, oid->oid_arg2,
1044		    req);
1045	return (error);
1046}
1047
1048#ifndef _SYS_SYSPROTO_H_
1049struct sysctl_args {
1050	int	*name;
1051	u_int	namelen;
1052	void	*old;
1053	size_t	*oldlenp;
1054	void	*new;
1055	size_t	newlen;
1056};
1057#endif
1058
1059int
1060__sysctl(struct proc *p, struct sysctl_args *uap)
1061{
1062	int error, i, name[CTL_MAXNAME];
1063	size_t j;
1064
1065	if (uap->namelen > CTL_MAXNAME || uap->namelen < 2)
1066		return (EINVAL);
1067
1068 	error = copyin(uap->name, &name, uap->namelen * sizeof(int));
1069 	if (error)
1070		return (error);
1071
1072	error = userland_sysctl(p, name, uap->namelen,
1073		uap->old, uap->oldlenp, 0,
1074		uap->new, uap->newlen, &j);
1075	if (error && error != ENOMEM)
1076		return (error);
1077	if (uap->oldlenp) {
1078		i = copyout(&j, uap->oldlenp, sizeof(j));
1079		if (i)
1080			return (i);
1081	}
1082	return (error);
1083}
1084
1085/*
1086 * This is used from various compatibility syscalls too.  That's why name
1087 * must be in kernel space.
1088 */
1089int
1090userland_sysctl(struct proc *p, int *name, u_int namelen, void *old,
1091    size_t *oldlenp, int inkernel, void *new, size_t newlen, size_t *retval)
1092{
1093	int error = 0;
1094	struct sysctl_req req, req2;
1095
1096	bzero(&req, sizeof req);
1097
1098	req.p = p;
1099
1100	if (oldlenp) {
1101		if (inkernel) {
1102			req.oldlen = *oldlenp;
1103		} else {
1104			error = copyin(oldlenp, &req.oldlen, sizeof(*oldlenp));
1105			if (error)
1106				return (error);
1107		}
1108	}
1109
1110	if (old) {
1111		if (!useracc(old, req.oldlen, VM_PROT_WRITE))
1112			return (EFAULT);
1113		req.oldptr= old;
1114	}
1115
1116	if (new != NULL) {
1117		if (!useracc(new, req.newlen, VM_PROT_READ))
1118			return (EFAULT);
1119		req.newlen = newlen;
1120		req.newptr = new;
1121	}
1122
1123	req.oldfunc = sysctl_old_user;
1124	req.newfunc = sysctl_new_user;
1125	req.lock = 1;
1126
1127	/* XXX this should probably be done in a general way */
1128	while (memlock.sl_lock) {
1129		memlock.sl_want = 1;
1130		(void) tsleep((caddr_t)&memlock, PRIBIO+1, "sysctl", 0);
1131		memlock.sl_locked++;
1132	}
1133	memlock.sl_lock = 1;
1134
1135	do {
1136	    req2 = req;
1137	    error = sysctl_root(0, name, namelen, &req2);
1138	} while (error == EAGAIN);
1139
1140	req = req2;
1141	if (req.lock == 2)
1142		vsunlock(req.oldptr, req.oldlen);
1143
1144	memlock.sl_lock = 0;
1145
1146	if (memlock.sl_want) {
1147		memlock.sl_want = 0;
1148		wakeup((caddr_t)&memlock);
1149	}
1150
1151	if (error && error != ENOMEM)
1152		return (error);
1153
1154	if (retval) {
1155		if (req.oldptr && req.oldidx > req.oldlen)
1156			*retval = req.oldlen;
1157		else
1158			*retval = req.oldidx;
1159	}
1160	return (error);
1161}
1162
1163#ifdef COMPAT_43
1164#include <sys/socket.h>
1165#include <vm/vm_param.h>
1166
1167#define	KINFO_PROC		(0<<8)
1168#define	KINFO_RT		(1<<8)
1169#define	KINFO_VNODE		(2<<8)
1170#define	KINFO_FILE		(3<<8)
1171#define	KINFO_METER		(4<<8)
1172#define	KINFO_LOADAVG		(5<<8)
1173#define	KINFO_CLOCKRATE		(6<<8)
1174
1175/* Non-standard BSDI extension - only present on their 4.3 net-2 releases */
1176#define	KINFO_BSDI_SYSINFO	(101<<8)
1177
1178/*
1179 * XXX this is bloat, but I hope it's better here than on the potentially
1180 * limited kernel stack...  -Peter
1181 */
1182
1183static struct {
1184	int	bsdi_machine;		/* "i386" on BSD/386 */
1185/*      ^^^ this is an offset to the string, relative to the struct start */
1186	char	*pad0;
1187	long	pad1;
1188	long	pad2;
1189	long	pad3;
1190	u_long	pad4;
1191	u_long	pad5;
1192	u_long	pad6;
1193
1194	int	bsdi_ostype;		/* "BSD/386" on BSD/386 */
1195	int	bsdi_osrelease;		/* "1.1" on BSD/386 */
1196	long	pad7;
1197	long	pad8;
1198	char	*pad9;
1199
1200	long	pad10;
1201	long	pad11;
1202	int	pad12;
1203	long	pad13;
1204	quad_t	pad14;
1205	long	pad15;
1206
1207	struct	timeval pad16;
1208	/* we dont set this, because BSDI's uname used gethostname() instead */
1209	int	bsdi_hostname;		/* hostname on BSD/386 */
1210
1211	/* the actual string data is appended here */
1212
1213} bsdi_si;
1214/*
1215 * this data is appended to the end of the bsdi_si structure during copyout.
1216 * The "char *" offsets are relative to the base of the bsdi_si struct.
1217 * This contains "FreeBSD\02.0-BUILT-nnnnnn\0i386\0", and these strings
1218 * should not exceed the length of the buffer here... (or else!! :-)
1219 */
1220static char bsdi_strings[80];	/* It had better be less than this! */
1221
1222#ifndef _SYS_SYSPROTO_H_
1223struct getkerninfo_args {
1224	int	op;
1225	char	*where;
1226	size_t	*size;
1227	int	arg;
1228};
1229#endif
1230
1231int
1232ogetkerninfo(struct proc *p, struct getkerninfo_args *uap)
1233{
1234	int error, name[6];
1235	size_t size;
1236
1237	switch (uap->op & 0xff00) {
1238
1239	case KINFO_RT:
1240		name[0] = CTL_NET;
1241		name[1] = PF_ROUTE;
1242		name[2] = 0;
1243		name[3] = (uap->op & 0xff0000) >> 16;
1244		name[4] = uap->op & 0xff;
1245		name[5] = uap->arg;
1246		error = userland_sysctl(p, name, 6, uap->where, uap->size,
1247			0, 0, 0, &size);
1248		break;
1249
1250	case KINFO_VNODE:
1251		name[0] = CTL_KERN;
1252		name[1] = KERN_VNODE;
1253		error = userland_sysctl(p, name, 2, uap->where, uap->size,
1254			0, 0, 0, &size);
1255		break;
1256
1257	case KINFO_PROC:
1258		name[0] = CTL_KERN;
1259		name[1] = KERN_PROC;
1260		name[2] = uap->op & 0xff;
1261		name[3] = uap->arg;
1262		error = userland_sysctl(p, name, 4, uap->where, uap->size,
1263			0, 0, 0, &size);
1264		break;
1265
1266	case KINFO_FILE:
1267		name[0] = CTL_KERN;
1268		name[1] = KERN_FILE;
1269		error = userland_sysctl(p, name, 2, uap->where, uap->size,
1270			0, 0, 0, &size);
1271		break;
1272
1273	case KINFO_METER:
1274		name[0] = CTL_VM;
1275		name[1] = VM_METER;
1276		error = userland_sysctl(p, name, 2, uap->where, uap->size,
1277			0, 0, 0, &size);
1278		break;
1279
1280	case KINFO_LOADAVG:
1281		name[0] = CTL_VM;
1282		name[1] = VM_LOADAVG;
1283		error = userland_sysctl(p, name, 2, uap->where, uap->size,
1284			0, 0, 0, &size);
1285		break;
1286
1287	case KINFO_CLOCKRATE:
1288		name[0] = CTL_KERN;
1289		name[1] = KERN_CLOCKRATE;
1290		error = userland_sysctl(p, name, 2, uap->where, uap->size,
1291			0, 0, 0, &size);
1292		break;
1293
1294	case KINFO_BSDI_SYSINFO: {
1295		/*
1296		 * this is pretty crude, but it's just enough for uname()
1297		 * from BSDI's 1.x libc to work.
1298		 *
1299		 * In particular, it doesn't return the same results when
1300		 * the supplied buffer is too small.  BSDI's version apparently
1301		 * will return the amount copied, and set the *size to how
1302		 * much was needed.  The emulation framework here isn't capable
1303		 * of that, so we just set both to the amount copied.
1304		 * BSDI's 2.x product apparently fails with ENOMEM in this
1305		 * scenario.
1306		 */
1307
1308		u_int needed;
1309		u_int left;
1310		char *s;
1311
1312		bzero((char *)&bsdi_si, sizeof(bsdi_si));
1313		bzero(bsdi_strings, sizeof(bsdi_strings));
1314
1315		s = bsdi_strings;
1316
1317		bsdi_si.bsdi_ostype = (s - bsdi_strings) + sizeof(bsdi_si);
1318		strcpy(s, ostype);
1319		s += strlen(s) + 1;
1320
1321		bsdi_si.bsdi_osrelease = (s - bsdi_strings) + sizeof(bsdi_si);
1322		strcpy(s, osrelease);
1323		s += strlen(s) + 1;
1324
1325		bsdi_si.bsdi_machine = (s - bsdi_strings) + sizeof(bsdi_si);
1326		strcpy(s, machine);
1327		s += strlen(s) + 1;
1328
1329		needed = sizeof(bsdi_si) + (s - bsdi_strings);
1330
1331		if (uap->where == NULL) {
1332			/* process is asking how much buffer to supply.. */
1333			size = needed;
1334			error = 0;
1335			break;
1336		}
1337
1338
1339		/* if too much buffer supplied, trim it down */
1340		if (size > needed)
1341			size = needed;
1342
1343		/* how much of the buffer is remaining */
1344		left = size;
1345
1346		if ((error = copyout((char *)&bsdi_si, uap->where, left)) != 0)
1347			break;
1348
1349		/* is there any point in continuing? */
1350		if (left > sizeof(bsdi_si)) {
1351			left -= sizeof(bsdi_si);
1352			error = copyout(&bsdi_strings,
1353					uap->where + sizeof(bsdi_si), left);
1354		}
1355		break;
1356	}
1357
1358	default:
1359		return (EOPNOTSUPP);
1360	}
1361	if (error)
1362		return (error);
1363	p->p_retval[0] = size;
1364	if (uap->size)
1365		error = copyout((caddr_t)&size, (caddr_t)uap->size,
1366		    sizeof(size));
1367	return (error);
1368}
1369#endif /* COMPAT_43 */
1370