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