]> git.saurik.com Git - apple/xnu.git/blame - bsd/kern/kern_newsysctl.c
xnu-517.tar.gz
[apple/xnu.git] / bsd / kern / kern_newsysctl.c
CommitLineData
1c79356b
A
1/*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
43866e37 6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
1c79356b 7 *
43866e37
A
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
1c79356b
A
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
43866e37
A
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
1c79356b
A
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25/*-
26 * Copyright (c) 1982, 1986, 1989, 1993
27 * The Regents of the University of California. All rights reserved.
28 *
29 * This code is derived from software contributed to Berkeley by
30 * Mike Karels at Berkeley Software Design, Inc.
31 *
32 * Quite extensively rewritten by Poul-Henning Kamp of the FreeBSD
33 * project, to make these variables more userfriendly.
34 *
35 * Redistribution and use in source and binary forms, with or without
36 * modification, are permitted provided that the following conditions
37 * are met:
38 * 1. Redistributions of source code must retain the above copyright
39 * notice, this list of conditions and the following disclaimer.
40 * 2. Redistributions in binary form must reproduce the above copyright
41 * notice, this list of conditions and the following disclaimer in the
42 * documentation and/or other materials provided with the distribution.
43 * 3. All advertising materials mentioning features or use of this software
44 * must display the following acknowledgement:
45 * This product includes software developed by the University of
46 * California, Berkeley and its contributors.
47 * 4. Neither the name of the University nor the names of its contributors
48 * may be used to endorse or promote products derived from this software
49 * without specific prior written permission.
50 *
51 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
52 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
53 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
54 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
55 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
56 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
57 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
58 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
59 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
60 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
61 * SUCH DAMAGE.
62 *
63 * @(#)kern_sysctl.c 8.4 (Berkeley) 4/14/94
64 */
65
66
67#include <sys/param.h>
68#include <sys/buf.h>
69#include <sys/kernel.h>
70#include <sys/sysctl.h>
71#include <sys/malloc.h>
72#include <sys/proc.h>
73#include <sys/systm.h>
74
75/*
76struct sysctl_oid_list sysctl__debug_children;
77struct sysctl_oid_list sysctl__kern_children;
78struct sysctl_oid_list sysctl__net_children;
79struct sysctl_oid_list sysctl__sysctl_children;
80*/
81
82extern struct sysctl_oid *newsysctl_list[];
55e303ae 83extern struct sysctl_oid *machdep_sysctl_list[];
1c79356b
A
84
85
86static void
87sysctl_sysctl_debug_dump_node(struct sysctl_oid_list *l, int i);
88
89
90
91/*
92 * Locking and stats
93 */
94static struct sysctl_lock {
95 int sl_lock;
96 int sl_want;
97 int sl_locked;
98} memlock;
99
43866e37
A
100/*
101 * XXX this does not belong here
102 */
103static funnel_t *
104spl_kernel_funnel(void)
105{
106 funnel_t *cfunnel;
107
108 cfunnel = thread_funnel_get();
109 if (cfunnel != kernel_flock) {
110 if (cfunnel != NULL)
111 thread_funnel_set(cfunnel, FALSE);
112 thread_funnel_set(kernel_flock, TRUE);
113 }
114 return(cfunnel);
115}
116
117static void
118splx_kernel_funnel(funnel_t *saved)
119{
120 if (saved != kernel_flock) {
121 thread_funnel_set(kernel_flock, FALSE);
122 if (saved != NULL)
123 thread_funnel_set(saved, TRUE);
124 }
125}
126
1c79356b
A
127static int sysctl_root SYSCTL_HANDLER_ARGS;
128
129struct sysctl_oid_list sysctl__children; /* root list */
130
131/*
132 * Initialization of the MIB tree.
133 *
134 * Order by number in each list.
135 */
136
137void sysctl_register_oid(struct sysctl_oid *oidp)
138{
139 struct sysctl_oid_list *parent = oidp->oid_parent;
140 struct sysctl_oid *p;
141 struct sysctl_oid *q;
142 int n;
43866e37
A
143 funnel_t *fnl;
144
145 fnl = spl_kernel_funnel();
1c79356b
A
146
147 /*
148 * If this oid has a number OID_AUTO, give it a number which
149 * is greater than any current oid. Make sure it is at least
150 * 100 to leave space for pre-assigned oid numbers.
151 */
152/* sysctl_sysctl_debug_dump_node(parent, 3); */
153 if (oidp->oid_number == OID_AUTO) {
154 /* First, find the highest oid in the parent list >99 */
155 n = 99;
156 SLIST_FOREACH(p, parent, oid_link) {
157 if (p->oid_number > n)
158 n = p->oid_number;
159 }
160 oidp->oid_number = n + 1;
161 }
162
163 /*
164 * Insert the oid into the parent's list in order.
165 */
166 q = NULL;
167 SLIST_FOREACH(p, parent, oid_link) {
168 if (oidp->oid_number < p->oid_number)
169 break;
170 q = p;
171 }
172 if (q)
173 SLIST_INSERT_AFTER(q, oidp, oid_link);
174 else
175 SLIST_INSERT_HEAD(parent, oidp, oid_link);
43866e37
A
176
177 splx_kernel_funnel(fnl);
1c79356b
A
178}
179
180void sysctl_unregister_oid(struct sysctl_oid *oidp)
181{
43866e37
A
182 funnel_t *fnl;
183
184 fnl = spl_kernel_funnel();
1c79356b 185 SLIST_REMOVE(oidp->oid_parent, oidp, sysctl_oid, oid_link);
43866e37 186 splx_kernel_funnel(fnl);
1c79356b
A
187}
188
189/*
190 * Bulk-register all the oids in a linker_set.
191 */
192void sysctl_register_set(struct linker_set *lsp)
193{
194 int count = lsp->ls_length;
195 int i;
196 for (i = 0; i < count; i++)
197 sysctl_register_oid((struct sysctl_oid *) lsp->ls_items[i]);
198}
199
200void sysctl_unregister_set(struct linker_set *lsp)
201{
202 int count = lsp->ls_length;
203 int i;
204 for (i = 0; i < count; i++)
205 sysctl_unregister_oid((struct sysctl_oid *) lsp->ls_items[i]);
206}
207
208
209/*
210 * Register OID's from fixed list
211 */
212
213void sysctl_register_fixed()
214{
55e303ae 215 int i;
1c79356b 216
55e303ae
A
217 for (i=0; newsysctl_list[i]; i++) {
218 sysctl_register_oid(newsysctl_list[i]);
219 }
220 for (i=0; machdep_sysctl_list[i]; i++) {
221 sysctl_register_oid(machdep_sysctl_list[i]);
1c79356b
A
222 }
223}
224
225/*
226 * Register the kernel's oids on startup.
227 */
228struct linker_set sysctl_set;
229
230void sysctl_register_all(void *arg)
231{
232 sysctl_register_set(&sysctl_set);
233}
234
235SYSINIT(sysctl, SI_SUB_KMEM, SI_ORDER_ANY, sysctl_register_all, 0);
236
237/*
238 * "Staff-functions"
239 *
240 * These functions implement a presently undocumented interface
241 * used by the sysctl program to walk the tree, and get the type
242 * so it can print the value.
243 * This interface is under work and consideration, and should probably
244 * be killed with a big axe by the first person who can find the time.
245 * (be aware though, that the proper interface isn't as obvious as it
246 * may seem, there are various conflicting requirements.
247 *
248 * {0,0} printf the entire MIB-tree.
249 * {0,1,...} return the name of the "..." OID.
250 * {0,2,...} return the next OID.
251 * {0,3} return the OID of the name in "new"
252 * {0,4,...} return the kind & format info for the "..." OID.
253 */
254
255static void
256sysctl_sysctl_debug_dump_node(struct sysctl_oid_list *l, int i)
257{
258 int k;
259 struct sysctl_oid *oidp;
260
261 SLIST_FOREACH(oidp, l, oid_link) {
262
263 for (k=0; k<i; k++)
264 printf(" ");
265
266 printf("%d %s ", oidp->oid_number, oidp->oid_name);
267
268 printf("%c%c",
269 oidp->oid_kind & CTLFLAG_RD ? 'R':' ',
270 oidp->oid_kind & CTLFLAG_WR ? 'W':' ');
271
272 if (oidp->oid_handler)
273 printf(" *Handler");
274
275 switch (oidp->oid_kind & CTLTYPE) {
276 case CTLTYPE_NODE:
277 printf(" Node\n");
278 if (!oidp->oid_handler) {
279 sysctl_sysctl_debug_dump_node(
280 oidp->oid_arg1, i+2);
281 }
282 break;
283 case CTLTYPE_INT: printf(" Int\n"); break;
284 case CTLTYPE_STRING: printf(" String\n"); break;
285 case CTLTYPE_QUAD: printf(" Quad\n"); break;
286 case CTLTYPE_OPAQUE: printf(" Opaque/struct\n"); break;
287 default: printf("\n");
288 }
289
290 }
291}
292
293static int
294sysctl_sysctl_debug SYSCTL_HANDLER_ARGS
295{
296 sysctl_sysctl_debug_dump_node(&sysctl__children, 0);
297 return ENOENT;
298}
299
300SYSCTL_PROC(_sysctl, 0, debug, CTLTYPE_STRING|CTLFLAG_RD,
301 0, 0, sysctl_sysctl_debug, "-", "");
302
303static int
304sysctl_sysctl_name SYSCTL_HANDLER_ARGS
305{
306 int *name = (int *) arg1;
307 u_int namelen = arg2;
308 int error = 0;
309 struct sysctl_oid *oid;
310 struct sysctl_oid_list *lsp = &sysctl__children, *lsp2;
311 char buf[10];
312
313 while (namelen) {
314 if (!lsp) {
315 snprintf(buf,sizeof(buf),"%d",*name);
316 if (req->oldidx)
317 error = SYSCTL_OUT(req, ".", 1);
318 if (!error)
319 error = SYSCTL_OUT(req, buf, strlen(buf));
320 if (error)
321 return (error);
322 namelen--;
323 name++;
324 continue;
325 }
326 lsp2 = 0;
327 SLIST_FOREACH(oid, lsp, oid_link) {
328 if (oid->oid_number != *name)
329 continue;
330
331 if (req->oldidx)
332 error = SYSCTL_OUT(req, ".", 1);
333 if (!error)
334 error = SYSCTL_OUT(req, oid->oid_name,
335 strlen(oid->oid_name));
336 if (error)
337 return (error);
338
339 namelen--;
340 name++;
341
342 if ((oid->oid_kind & CTLTYPE) != CTLTYPE_NODE)
343 break;
344
345 if (oid->oid_handler)
346 break;
347
348 lsp2 = (struct sysctl_oid_list *)oid->oid_arg1;
349 break;
350 }
351 lsp = lsp2;
352 }
353 return (SYSCTL_OUT(req, "", 1));
354}
355
356SYSCTL_NODE(_sysctl, 1, name, CTLFLAG_RD, sysctl_sysctl_name, "");
357
358static int
359sysctl_sysctl_next_ls (struct sysctl_oid_list *lsp, int *name, u_int namelen,
360 int *next, int *len, int level, struct sysctl_oid **oidpp)
361{
362 struct sysctl_oid *oidp;
363
364 *len = level;
365 SLIST_FOREACH(oidp, lsp, oid_link) {
366 *next = oidp->oid_number;
367 *oidpp = oidp;
368
369 if (!namelen) {
370 if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE)
371 return 0;
372 if (oidp->oid_handler)
373 /* We really should call the handler here...*/
374 return 0;
375 lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
376 if (!sysctl_sysctl_next_ls (lsp, 0, 0, next+1,
377 len, level+1, oidpp))
378 return 0;
379 goto next;
380 }
381
382 if (oidp->oid_number < *name)
383 continue;
384
385 if (oidp->oid_number > *name) {
386 if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE)
387 return 0;
388 if (oidp->oid_handler)
389 return 0;
390 lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
391 if (!sysctl_sysctl_next_ls (lsp, name+1, namelen-1,
392 next+1, len, level+1, oidpp))
393 return (0);
394 goto next;
395 }
396 if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE)
397 continue;
398
399 if (oidp->oid_handler)
400 continue;
401
402 lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
403 if (!sysctl_sysctl_next_ls (lsp, name+1, namelen-1, next+1,
404 len, level+1, oidpp))
405 return (0);
406 next:
407 namelen = 1;
408 *len = level;
409 }
410 return 1;
411}
412
413static int
414sysctl_sysctl_next SYSCTL_HANDLER_ARGS
415{
416 int *name = (int *) arg1;
417 u_int namelen = arg2;
418 int i, j, error;
419 struct sysctl_oid *oid;
420 struct sysctl_oid_list *lsp = &sysctl__children;
421 int newoid[CTL_MAXNAME];
422
423 i = sysctl_sysctl_next_ls (lsp, name, namelen, newoid, &j, 1, &oid);
424 if (i)
425 return ENOENT;
426 error = SYSCTL_OUT(req, newoid, j * sizeof (int));
427 return (error);
428}
429
430SYSCTL_NODE(_sysctl, 2, next, CTLFLAG_RD, sysctl_sysctl_next, "");
431
432static int
433name2oid (char *name, int *oid, int *len, struct sysctl_oid **oidpp)
434{
435 int i;
436 struct sysctl_oid *oidp;
437 struct sysctl_oid_list *lsp = &sysctl__children;
438 char *p;
439
440 if (!*name)
441 return ENOENT;
442
443 p = name + strlen(name) - 1 ;
444 if (*p == '.')
445 *p = '\0';
446
447 *len = 0;
448
449 for (p = name; *p && *p != '.'; p++)
450 ;
451 i = *p;
452 if (i == '.')
453 *p = '\0';
454
455 oidp = SLIST_FIRST(lsp);
456
457 while (oidp && *len < CTL_MAXNAME) {
458 if (strcmp(name, oidp->oid_name)) {
459 oidp = SLIST_NEXT(oidp, oid_link);
460 continue;
461 }
462 *oid++ = oidp->oid_number;
463 (*len)++;
464
465 if (!i) {
466 if (oidpp)
467 *oidpp = oidp;
468 return (0);
469 }
470
471 if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE)
472 break;
473
474 if (oidp->oid_handler)
475 break;
476
477 lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
478 oidp = SLIST_FIRST(lsp);
479 name = p+1;
480 for (p = name; *p && *p != '.'; p++)
481 ;
482 i = *p;
483 if (i == '.')
484 *p = '\0';
485 }
486 return ENOENT;
487}
488
489static int
490sysctl_sysctl_name2oid SYSCTL_HANDLER_ARGS
491{
492 char *p;
493 int error, oid[CTL_MAXNAME], len;
494 struct sysctl_oid *op = 0;
495
496 if (!req->newlen)
497 return ENOENT;
498 if (req->newlen >= MAXPATHLEN) /* XXX arbitrary, undocumented */
499 return (ENAMETOOLONG);
500
501 p = _MALLOC(req->newlen+1, M_TEMP, M_WAITOK);
502
503 if (!p)
504 return ENOMEM;
505
506 error = SYSCTL_IN(req, p, req->newlen);
507 if (error) {
508 FREE(p, M_TEMP);
509 return (error);
510 }
511
512 p [req->newlen] = '\0';
513
514 error = name2oid(p, oid, &len, &op);
515
516 FREE(p, M_TEMP);
517
518 if (error)
519 return (error);
520
521 error = SYSCTL_OUT(req, oid, len * sizeof *oid);
522 return (error);
523}
524
525SYSCTL_PROC(_sysctl, 3, name2oid, CTLFLAG_RW|CTLFLAG_ANYBODY, 0, 0,
526 sysctl_sysctl_name2oid, "I", "");
527
528static int
529sysctl_sysctl_oidfmt SYSCTL_HANDLER_ARGS
530{
531 int *name = (int *) arg1, error;
532 u_int namelen = arg2;
533 int indx;
534 struct sysctl_oid *oid;
535 struct sysctl_oid_list *lsp = &sysctl__children;
536
537 oid = SLIST_FIRST(lsp);
538
539 indx = 0;
540 while (oid && indx < CTL_MAXNAME) {
541 if (oid->oid_number == name[indx]) {
542 indx++;
543 if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
544 if (oid->oid_handler)
545 goto found;
546 if (indx == namelen)
547 goto found;
548 lsp = (struct sysctl_oid_list *)oid->oid_arg1;
549 oid = SLIST_FIRST(lsp);
550 } else {
551 if (indx != namelen)
552 return EISDIR;
553 goto found;
554 }
555 } else {
556 oid = SLIST_NEXT(oid, oid_link);
557 }
558 }
559 return ENOENT;
560found:
561 if (!oid->oid_fmt)
562 return ENOENT;
563 error = SYSCTL_OUT(req,
564 &oid->oid_kind, sizeof(oid->oid_kind));
565 if (!error)
566 error = SYSCTL_OUT(req, oid->oid_fmt,
567 strlen(oid->oid_fmt)+1);
568 return (error);
569}
570
571
572SYSCTL_NODE(_sysctl, 4, oidfmt, CTLFLAG_RD, sysctl_sysctl_oidfmt, "");
573
574/*
575 * Default "handler" functions.
576 */
577
578/*
579 * Handle an int, signed or unsigned.
580 * Two cases:
581 * a variable: point arg1 at it.
582 * a constant: pass it in arg2.
583 */
584
585int
586sysctl_handle_int SYSCTL_HANDLER_ARGS
587{
588 int error = 0;
589
590 if (arg1)
591 error = SYSCTL_OUT(req, arg1, sizeof(int));
592 else
593 error = SYSCTL_OUT(req, &arg2, sizeof(int));
594
595 if (error || !req->newptr)
596 return (error);
597
598 if (!arg1)
599 error = EPERM;
600 else
601 error = SYSCTL_IN(req, arg1, sizeof(int));
602 return (error);
603}
604
605/*
606 * Handle a long, signed or unsigned. arg1 points to it.
607 */
608
609int
610sysctl_handle_long SYSCTL_HANDLER_ARGS
611{
612 int error = 0;
613
614 if (!arg1)
615 return (EINVAL);
616 error = SYSCTL_OUT(req, arg1, sizeof(long));
617
618 if (error || !req->newptr)
619 return (error);
620
621 error = SYSCTL_IN(req, arg1, sizeof(long));
622 return (error);
623}
624
43866e37
A
625/*
626 * Handle a quad, signed or unsigned. arg1 points to it.
627 */
628
629int
630sysctl_handle_quad SYSCTL_HANDLER_ARGS
631{
632 int error = 0;
633
634 if (!arg1)
635 return (EINVAL);
636 error = SYSCTL_OUT(req, arg1, sizeof(long long));
637
638 if (error || !req->newptr)
639 return (error);
640
641 error = SYSCTL_IN(req, arg1, sizeof(long long));
642 return (error);
643}
644
645/*
646 * Expose an int value as a quad.
647 *
648 * This interface allows us to support interfaces defined
649 * as using quad values while the implementation is still
650 * using ints.
651 */
652int
653sysctl_handle_int2quad SYSCTL_HANDLER_ARGS
654{
655 int error = 0;
656 long long val;
657 int newval;
658
659 if (!arg1)
660 return (EINVAL);
661 val = (long long)*(int *)arg1;
662 error = SYSCTL_OUT(req, &val, sizeof(long long));
663
664 if (error || !req->newptr)
665 return (error);
666
667 error = SYSCTL_IN(req, &val, sizeof(long long));
668 if (!error) {
669 /*
670 * Value must be representable; check by
671 * casting and then casting back.
672 */
673 newval = (int)val;
674 if ((long long)newval != val) {
675 error = ERANGE;
676 } else {
677 *(int *)arg1 = newval;
678 }
679 }
680 return (error);
681}
682
1c79356b
A
683/*
684 * Handle our generic '\0' terminated 'C' string.
685 * Two cases:
686 * a variable string: point arg1 at it, arg2 is max length.
687 * a constant string: point arg1 at it, arg2 is zero.
688 */
689
690int
691sysctl_handle_string SYSCTL_HANDLER_ARGS
692{
693 int error=0;
694
695 error = SYSCTL_OUT(req, arg1, strlen((char *)arg1)+1);
696
697 if (error || !req->newptr)
698 return (error);
699
700 if ((req->newlen - req->newidx) >= arg2) {
701 error = EINVAL;
702 } else {
703 arg2 = (req->newlen - req->newidx);
704 error = SYSCTL_IN(req, arg1, arg2);
705 ((char *)arg1)[arg2] = '\0';
706 }
707
708 return (error);
709}
710
711/*
712 * Handle any kind of opaque data.
713 * arg1 points to it, arg2 is the size.
714 */
715
716int
717sysctl_handle_opaque SYSCTL_HANDLER_ARGS
718{
719 int error;
720
721 error = SYSCTL_OUT(req, arg1, arg2);
722
723 if (error || !req->newptr)
724 return (error);
725
726 error = SYSCTL_IN(req, arg1, arg2);
727
728 return (error);
729}
730
731/*
732 * Transfer functions to/from kernel space.
1c79356b
A
733 */
734static int
735sysctl_old_kernel(struct sysctl_req *req, const void *p, size_t l)
736{
737 size_t i = 0;
738 int error = 0;
739
740 if (req->oldptr) {
741 i = l;
742 if (i > req->oldlen - req->oldidx)
743 i = req->oldlen - req->oldidx;
43866e37
A
744 if (i > 0)
745 bcopy((void*)p, (char *)req->oldptr + req->oldidx, i);
1c79356b
A
746 }
747 req->oldidx += l;
748 if (req->oldptr && i != l)
749 return (ENOMEM);
750 return (0);
751}
752
753static int
754sysctl_new_kernel(struct sysctl_req *req, void *p, size_t l)
755{
756 if (!req->newptr)
757 return 0;
758 if (req->newlen - req->newidx < l)
759 return (EINVAL);
43866e37 760 bcopy((char *)req->newptr + req->newidx, p, l);
1c79356b
A
761 req->newidx += l;
762 return (0);
763}
764
765int
43866e37 766kernel_sysctl(struct proc *p, int *name, u_int namelen, void *old, size_t *oldlenp, void *new, size_t newlen)
1c79356b
A
767{
768 int error = 0;
769 struct sysctl_req req;
43866e37 770 funnel_t *fnl;
1c79356b 771
43866e37
A
772 /*
773 * Construct request.
774 */
1c79356b 775 bzero(&req, sizeof req);
1c79356b 776 req.p = p;
43866e37 777 if (oldlenp)
1c79356b 778 req.oldlen = *oldlenp;
43866e37 779 if (old)
1c79356b 780 req.oldptr= old;
1c79356b
A
781 if (newlen) {
782 req.newlen = newlen;
783 req.newptr = new;
784 }
1c79356b
A
785 req.oldfunc = sysctl_old_kernel;
786 req.newfunc = sysctl_new_kernel;
787 req.lock = 1;
788
43866e37
A
789 /*
790 * Locking. Tree traversal always begins with the kernel funnel held.
791 */
792 fnl = spl_kernel_funnel();
793
1c79356b
A
794 /* XXX this should probably be done in a general way */
795 while (memlock.sl_lock) {
796 memlock.sl_want = 1;
797 (void) tsleep((caddr_t)&memlock, PRIBIO+1, "sysctl", 0);
798 memlock.sl_locked++;
799 }
800 memlock.sl_lock = 1;
801
43866e37 802 /* make the request */
1c79356b
A
803 error = sysctl_root(0, name, namelen, &req);
804
43866e37 805 /* unlock memory if required */
1c79356b
A
806 if (req.lock == 2)
807 vsunlock(req.oldptr, req.oldlen, B_WRITE);
808
809 memlock.sl_lock = 0;
810
811 if (memlock.sl_want) {
812 memlock.sl_want = 0;
813 wakeup((caddr_t)&memlock);
814 }
815
43866e37
A
816 /*
817 * Undo locking.
818 */
819 splx_kernel_funnel(fnl);
820
1c79356b
A
821 if (error && error != ENOMEM)
822 return (error);
823
43866e37
A
824 if (oldlenp)
825 *oldlenp = req.oldidx;
826
1c79356b
A
827 return (error);
828}
829
830/*
831 * Transfer function to/from user space.
832 */
833static int
834sysctl_old_user(struct sysctl_req *req, const void *p, size_t l)
835{
836 int error = 0;
837 size_t i = 0;
838
839 if (req->oldptr) {
840 if (req->oldlen - req->oldidx < l)
841 return (ENOMEM);
842 i = l;
843 if (i > req->oldlen - req->oldidx)
844 i = req->oldlen - req->oldidx;
845 if (i > 0)
9bccf70c 846 error = copyout((void*)p, (char *)req->oldptr + req->oldidx,
1c79356b
A
847 i);
848 }
849 req->oldidx += l;
850 if (error)
851 return (error);
852 if (req->oldptr && i < l)
853 return (ENOMEM);
854 return (0);
855}
856
857static int
858sysctl_new_user(struct sysctl_req *req, void *p, size_t l)
859{
860 int error;
861
862 if (!req->newptr)
863 return 0;
864 if (req->newlen - req->newidx < l)
865 return (EINVAL);
866 error = copyin((char *)req->newptr + req->newidx, p, l);
867 req->newidx += l;
868 return (error);
869}
870
871/*
872 * Traverse our tree, and find the right node, execute whatever it points
873 * at, and return the resulting error code.
874 */
875
876int
877sysctl_root SYSCTL_HANDLER_ARGS
878{
879 int *name = (int *) arg1;
880 u_int namelen = arg2;
881 int indx, i;
882 struct sysctl_oid *oid;
883 struct sysctl_oid_list *lsp = &sysctl__children;
884 int error;
885
886 oid = SLIST_FIRST(lsp);
887
888 indx = 0;
889 while (oid && indx < CTL_MAXNAME) {
890 if (oid->oid_number == name[indx]) {
891 indx++;
892 if (oid->oid_kind & CTLFLAG_NOLOCK)
893 req->lock = 0;
894 if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
895 if (oid->oid_handler)
896 goto found;
897 if (indx == namelen)
898 return ENOENT;
899 lsp = (struct sysctl_oid_list *)oid->oid_arg1;
900 oid = SLIST_FIRST(lsp);
901 } else {
902 if (indx != namelen)
903 return EISDIR;
904 goto found;
905 }
906 } else {
907 oid = SLIST_NEXT(oid, oid_link);
908 }
909 }
910 return ENOENT;
911found:
912 /* If writing isn't allowed */
913 if (req->newptr && (!(oid->oid_kind & CTLFLAG_WR) ||
914 ((oid->oid_kind & CTLFLAG_SECURE) && securelevel > 0))) {
915 return (EPERM);
916 }
917
43866e37
A
918 /*
919 * If we're inside the kernel, the OID must be marked as kernel-valid.
920 * XXX This mechanism for testing is bad.
921 */
922 if ((req->oldfunc == sysctl_old_kernel) && !(oid->oid_kind & CTLFLAG_KERN))
923 return(EPERM);
924
1c79356b
A
925 /* Most likely only root can write */
926 if (!(oid->oid_kind & CTLFLAG_ANYBODY) &&
927 req->newptr && req->p &&
928 (error = suser(req->p->p_ucred, &req->p->p_acflag)))
929 return (error);
930
931 if (!oid->oid_handler) {
932 return EINVAL;
933 }
934
935 /*
936 * Switch to the NETWORK funnel for CTL_NET and KERN_IPC sysctls
937 */
938
0b4e3aa0 939 if (((name[0] == CTL_NET) || ((name[0] == CTL_KERN) &&
1c79356b
A
940 (name[1] == KERN_IPC))))
941 thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL);
942
943 if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
944 i = (oid->oid_handler) (oid,
945 name + indx, namelen - indx,
946 req);
947 } else {
948 i = (oid->oid_handler) (oid,
949 oid->oid_arg1, oid->oid_arg2,
950 req);
951 }
952
953 /*
954 * Switch back to the KERNEL funnel, if necessary
955 */
956
0b4e3aa0 957 if (((name[0] == CTL_NET) || ((name[0] == CTL_KERN) &&
1c79356b
A
958 (name[1] == KERN_IPC))))
959 thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
960
961 return (i);
962}
963
964#ifndef _SYS_SYSPROTO_H_
965struct sysctl_args {
966 int *name;
967 u_int namelen;
968 void *old;
969 size_t *oldlenp;
970 void *new;
971 size_t newlen;
972};
973#endif
974
975int
976/* __sysctl(struct proc *p, struct sysctl_args *uap) */
977new_sysctl(struct proc *p, struct sysctl_args *uap)
978{
979 int error, i, name[CTL_MAXNAME];
980 size_t j;
981
982 if (uap->namelen > CTL_MAXNAME || uap->namelen < 2)
983 return (EINVAL);
984
985 error = copyin(uap->name, &name, uap->namelen * sizeof(int));
986 if (error)
987 return (error);
988
989 error = userland_sysctl(p, name, uap->namelen,
990 uap->old, uap->oldlenp, 0,
991 uap->new, uap->newlen, &j);
992 if (error && error != ENOMEM)
993 return (error);
994 if (uap->oldlenp) {
995 i = copyout(&j, uap->oldlenp, sizeof(j));
996 if (i)
997 return (i);
998 }
999 return (error);
1000}
1001
1002/*
1003 * This is used from various compatibility syscalls too. That's why name
1004 * must be in kernel space.
1005 */
1006int
1007userland_sysctl(struct proc *p, int *name, u_int namelen, void *old, size_t *oldlenp, int inkernel, void *new, size_t newlen, size_t *retval)
1008{
1009 int error = 0;
1010 struct sysctl_req req, req2;
1011
1012 bzero(&req, sizeof req);
1013
1014 req.p = p;
1015
1016 if (oldlenp) {
1017 if (inkernel) {
1018 req.oldlen = *oldlenp;
1019 } else {
1020 error = copyin(oldlenp, &req.oldlen, sizeof(*oldlenp));
1021 if (error)
1022 return (error);
1023 }
1024 }
1025
1026 if (old) {
1027 req.oldptr= old;
1028 }
1029
1030 if (newlen) {
1031 req.newlen = newlen;
1032 req.newptr = new;
1033 }
1034
1035 req.oldfunc = sysctl_old_user;
1036 req.newfunc = sysctl_new_user;
1037 req.lock = 1;
1038
1039 do {
1040 req2 = req;
1041 error = sysctl_root(0, name, namelen, &req2);
1042 } while (error == EAGAIN);
1043
1044 req = req2;
1045
1046 if (error && error != ENOMEM)
1047 return (error);
1048
1049 if (retval) {
1050 if (req.oldptr && req.oldidx > req.oldlen)
1051 *retval = req.oldlen;
1052 else
1053 *retval = req.oldidx;
1054 }
1055 return (error);
1056}
1c79356b 1057
55e303ae
A
1058/* Non-standard BSDI extension - only present on their 4.3 net-2 releases */
1059#define KINFO_BSDI_SYSINFO (101<<8)
1060
1c79356b 1061/*
43866e37
A
1062 * Kernel versions of the userland sysctl helper functions.
1063 *
1064 * These allow sysctl to be used in the same fashion in both
1065 * userland and the kernel.
1066 *
1067 * Note that some sysctl handlers use copyin/copyout, which
1068 * may not work correctly.
de355530 1069 */
1c79356b 1070
43866e37
A
1071static int
1072sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, size_t newlen)
d7e50217 1073{
1c79356b 1074
43866e37
A
1075 return(kernel_sysctl(current_proc(), name, namelen, oldp, oldlenp, newp, newlen));
1076}
de355530 1077
43866e37
A
1078static int
1079sysctlnametomib(const char *name, int *mibp, size_t *sizep)
1080{
1081 int oid[2];
1082 int error;
de355530 1083
43866e37
A
1084 /* magic service node */
1085 oid[0] = 0;
1086 oid[1] = 3;
de355530 1087
43866e37
A
1088 /* look up OID for name */
1089 *sizep *= sizeof(int);
1090 error = sysctl(oid, 2, mibp, sizep, (void *)name, strlen(name));
1091 *sizep /= sizeof(int);
1092 return(error);
1093}
de355530 1094
43866e37
A
1095int
1096sysctlbyname(const char *name, void *oldp, size_t *oldlenp, void *newp, size_t newlen)
1097{
1098 int oid[CTL_MAXNAME + 2];
1099 int error;
1100 size_t oidlen;
de355530 1101
43866e37
A
1102 /* look up the OID */
1103 oidlen = CTL_MAXNAME;
1104 error = sysctlnametomib(name, oid, &oidlen);
de355530 1105
43866e37
A
1106 /* now use the OID */
1107 if (error == 0)
1108 error = sysctl(oid, oidlen, oldp, oldlenp, newp, newlen);
1109 return(error);
1c79356b 1110}
1c79356b 1111