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