2 * Copyright (c) 2000-2008 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 * Copyright (c) 1982, 1986, 1989, 1993
30 * The Regents of the University of California. All rights reserved.
32 * This code is derived from software contributed to Berkeley by
33 * Mike Karels at Berkeley Software Design, Inc.
35 * Quite extensively rewritten by Poul-Henning Kamp of the FreeBSD
36 * project, to make these variables more userfriendly.
38 * Redistribution and use in source and binary forms, with or without
39 * modification, are permitted provided that the following conditions
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.
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
66 * @(#)kern_sysctl.c 8.4 (Berkeley) 4/14/94
70 #include <sys/param.h>
72 #include <sys/kernel.h>
73 #include <sys/sysctl.h>
74 #include <sys/malloc.h>
75 #include <sys/proc_internal.h>
76 #include <sys/systm.h>
78 #include <security/audit/audit.h>
81 struct sysctl_oid_list sysctl__debug_children;
82 struct sysctl_oid_list sysctl__kern_children;
83 struct sysctl_oid_list sysctl__net_children;
84 struct sysctl_oid_list sysctl__sysctl_children;
87 lck_rw_t
* sysctl_geometry_lock
= NULL
;
90 sysctl_sysctl_debug_dump_node(struct sysctl_oid_list
*l
, int i
);
97 static struct sysctl_lock memlock
;
100 * XXX this does not belong here
103 spl_kernel_funnel(void)
107 cfunnel
= thread_funnel_get();
108 if (cfunnel
!= kernel_flock
) {
110 thread_funnel_set(cfunnel
, FALSE
);
111 thread_funnel_set(kernel_flock
, TRUE
);
117 splx_kernel_funnel(funnel_t
*saved
)
119 if (saved
!= kernel_flock
) {
120 thread_funnel_set(kernel_flock
, FALSE
);
122 thread_funnel_set(saved
, TRUE
);
126 static int sysctl_root SYSCTL_HANDLER_ARGS
;
128 struct sysctl_oid_list sysctl__children
; /* root list */
131 * Initialization of the MIB tree.
133 * Order by number in each list.
136 void sysctl_register_oid(struct sysctl_oid
*oidp
)
138 struct sysctl_oid_list
*parent
= oidp
->oid_parent
;
139 struct sysctl_oid
*p
;
140 struct sysctl_oid
*q
;
144 fnl
= spl_kernel_funnel();
146 if(sysctl_geometry_lock
== NULL
)
148 /* Initialise the geometry lock for reading/modifying the sysctl tree
149 * This is done here because IOKit registers some sysctls before bsd_init()
150 * calls sysctl_register_fixed().
153 lck_grp_t
* lck_grp
= lck_grp_alloc_init("sysctl", NULL
);
154 sysctl_geometry_lock
= lck_rw_alloc_init(lck_grp
, NULL
);
156 /* Get the write lock to modify the geometry */
157 lck_rw_lock_exclusive(sysctl_geometry_lock
);
160 * If this oid has a number OID_AUTO, give it a number which
161 * is greater than any current oid. Make sure it is at least
162 * OID_AUTO_START to leave space for pre-assigned oid numbers.
164 if (oidp
->oid_number
== OID_AUTO
) {
165 /* First, find the highest oid in the parent list >OID_AUTO_START-1 */
167 SLIST_FOREACH(p
, parent
, oid_link
) {
168 if (p
->oid_number
> n
)
171 oidp
->oid_number
= n
+ 1;
175 * Insert the oid into the parent's list in order.
178 SLIST_FOREACH(p
, parent
, oid_link
) {
179 if (oidp
->oid_number
< p
->oid_number
)
184 SLIST_INSERT_AFTER(q
, oidp
, oid_link
);
186 SLIST_INSERT_HEAD(parent
, oidp
, oid_link
);
188 /* Release the write lock */
189 lck_rw_unlock_exclusive(sysctl_geometry_lock
);
191 splx_kernel_funnel(fnl
);
194 void sysctl_unregister_oid(struct sysctl_oid
*oidp
)
198 fnl
= spl_kernel_funnel();
200 /* Get the write lock to modify the geometry */
201 lck_rw_lock_exclusive(sysctl_geometry_lock
);
203 SLIST_REMOVE(oidp
->oid_parent
, oidp
, sysctl_oid
, oid_link
);
205 /* Release the write lock */
206 lck_rw_unlock_exclusive(sysctl_geometry_lock
);
208 splx_kernel_funnel(fnl
);
212 * Bulk-register all the oids in a linker_set.
214 void sysctl_register_set(const char *set
)
216 struct sysctl_oid
**oidpp
, *oidp
;
218 LINKER_SET_FOREACH(oidpp
, struct sysctl_oid
**, set
) {
220 if (!(oidp
->oid_kind
& CTLFLAG_NOAUTO
)) {
221 sysctl_register_oid(oidp
);
226 void sysctl_unregister_set(const char *set
)
228 struct sysctl_oid
**oidpp
, *oidp
;
230 LINKER_SET_FOREACH(oidpp
, struct sysctl_oid
**, set
) {
232 if (!(oidp
->oid_kind
& CTLFLAG_NOAUTO
)) {
233 sysctl_unregister_oid(oidp
);
240 * Register the kernel's oids on startup.
244 sysctl_register_all()
246 sysctl_register_set("__sysctl_set");
250 sysctl_register_fixed(void)
252 sysctl_register_all();
256 * New handler interface
257 * If the sysctl caller (user mode or kernel mode) is interested in the
258 * value (req->oldptr != NULL), we copy the data (bigValue etc.) out,
259 * if the caller wants to set the value (req->newptr), we copy
260 * the data in (*pValue etc.).
264 sysctl_io_number(struct sysctl_req
*req
, long long bigValue
, size_t valueSize
, void *pValue
, int *changed
) {
268 if (changed
) *changed
= 0;
271 * Handle the various combinations of caller buffer size and
272 * data value size. We are generous in the case where the
273 * caller has specified a 32-bit buffer but the value is 64-bit
277 /* 32 bit value expected or 32 bit buffer offered */
278 if (((valueSize
== sizeof(int)) ||
279 ((req
->oldlen
== sizeof(int)) && (valueSize
== sizeof(long long))))
281 smallValue
= (int)bigValue
;
282 if ((long long)smallValue
!= bigValue
)
284 error
= SYSCTL_OUT(req
, &smallValue
, sizeof(smallValue
));
286 /* any other case is either size-equal or a bug */
287 error
= SYSCTL_OUT(req
, &bigValue
, valueSize
);
289 /* error or nothing to set */
290 if (error
|| !req
->newptr
)
293 /* set request for constant */
297 /* set request needs to convert? */
298 if ((req
->newlen
== sizeof(int)) && (valueSize
== sizeof(long long))) {
299 /* new value is 32 bits, upconvert to 64 bits */
300 error
= SYSCTL_IN(req
, &smallValue
, sizeof(smallValue
));
302 *(long long *)pValue
= (long long)smallValue
;
303 } else if ((req
->newlen
== sizeof(long long)) && (valueSize
== sizeof(int))) {
304 /* new value is 64 bits, downconvert to 32 bits and range check */
305 error
= SYSCTL_IN(req
, &bigValue
, sizeof(bigValue
));
307 smallValue
= (int)bigValue
;
308 if ((long long)smallValue
!= bigValue
)
310 *(int *)pValue
= smallValue
;
313 /* sizes match, just copy in */
314 error
= SYSCTL_IN(req
, pValue
, valueSize
);
316 if (!error
&& changed
)
322 sysctl_io_string(struct sysctl_req
*req
, char *pValue
, size_t valueSize
, int trunc
, int *changed
)
326 if (changed
) *changed
= 0;
328 if (trunc
&& req
->oldptr
&& req
->oldlen
&& (req
->oldlen
<strlen(pValue
) + 1)) {
329 /* If trunc != 0, if you give it a too small (but larger than
330 * 0 bytes) buffer, instead of returning ENOMEM, it truncates the
331 * returned string to the buffer size. This preserves the semantics
332 * of some library routines implemented via sysctl, which truncate
333 * their returned data, rather than simply returning an error. The
334 * returned string is always NUL terminated. */
335 error
= SYSCTL_OUT(req
, pValue
, req
->oldlen
-1);
338 error
= SYSCTL_OUT(req
, &c
, 1);
341 /* Copy string out */
342 error
= SYSCTL_OUT(req
, pValue
, strlen(pValue
) + 1);
345 /* error or no new value */
346 if (error
|| !req
->newptr
)
349 /* attempt to set read-only value */
353 /* make sure there's room for the new string */
354 if (req
->newlen
>= valueSize
)
357 /* copy the string in and force NUL termination */
358 error
= SYSCTL_IN(req
, pValue
, req
->newlen
);
359 pValue
[req
->newlen
] = '\0';
361 if (!error
&& changed
)
366 int sysctl_io_opaque(struct sysctl_req
*req
,void *pValue
, size_t valueSize
, int *changed
)
370 if (changed
) *changed
= 0;
373 error
= SYSCTL_OUT(req
, pValue
, valueSize
);
375 /* error or nothing to set */
376 if (error
|| !req
->newptr
)
379 error
= SYSCTL_IN(req
, pValue
, valueSize
);
381 if (!error
&& changed
)
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.
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.
405 sysctl_sysctl_debug_dump_node(struct sysctl_oid_list
*l
, int i
)
408 struct sysctl_oid
*oidp
;
410 SLIST_FOREACH(oidp
, l
, oid_link
) {
415 printf("%d %s ", oidp
->oid_number
, oidp
->oid_name
);
418 oidp
->oid_kind
& CTLFLAG_RD
? 'R':' ',
419 oidp
->oid_kind
& CTLFLAG_WR
? 'W':' ');
421 if (oidp
->oid_handler
)
424 switch (oidp
->oid_kind
& CTLTYPE
) {
427 if (!oidp
->oid_handler
) {
428 sysctl_sysctl_debug_dump_node(
429 oidp
->oid_arg1
, i
+2);
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");
443 sysctl_sysctl_debug(__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
,
444 __unused
int arg2
, __unused
struct sysctl_req
*req
)
446 sysctl_sysctl_debug_dump_node(&sysctl__children
, 0);
450 SYSCTL_PROC(_sysctl
, 0, debug
, CTLTYPE_STRING
|CTLFLAG_RD
,
451 0, 0, sysctl_sysctl_debug
, "-", "");
454 sysctl_sysctl_name(__unused
struct sysctl_oid
*oidp
, void *arg1
, int arg2
,
455 struct sysctl_req
*req
)
457 int *name
= (int *) arg1
;
458 u_int namelen
= arg2
;
460 struct sysctl_oid
*oid
;
461 struct sysctl_oid_list
*lsp
= &sysctl__children
, *lsp2
;
466 snprintf(tempbuf
,sizeof(tempbuf
),"%d",*name
);
468 error
= SYSCTL_OUT(req
, ".", 1);
470 error
= SYSCTL_OUT(req
, tempbuf
, strlen(tempbuf
));
478 SLIST_FOREACH(oid
, lsp
, oid_link
) {
479 if (oid
->oid_number
!= *name
)
483 error
= SYSCTL_OUT(req
, ".", 1);
485 error
= SYSCTL_OUT(req
, oid
->oid_name
,
486 strlen(oid
->oid_name
));
493 if ((oid
->oid_kind
& CTLTYPE
) != CTLTYPE_NODE
)
496 if (oid
->oid_handler
)
499 lsp2
= (struct sysctl_oid_list
*)oid
->oid_arg1
;
504 return (SYSCTL_OUT(req
, "", 1));
507 SYSCTL_NODE(_sysctl
, 1, name
, CTLFLAG_RD
, sysctl_sysctl_name
, "");
510 sysctl_sysctl_next_ls (struct sysctl_oid_list
*lsp
, int *name
, u_int namelen
,
511 int *next
, int *len
, int level
, struct sysctl_oid
**oidpp
)
513 struct sysctl_oid
*oidp
;
516 SLIST_FOREACH(oidp
, lsp
, oid_link
) {
517 *next
= oidp
->oid_number
;
521 if ((oidp
->oid_kind
& CTLTYPE
) != CTLTYPE_NODE
)
523 if (oidp
->oid_handler
)
524 /* We really should call the handler here...*/
526 lsp
= (struct sysctl_oid_list
*)oidp
->oid_arg1
;
528 if (!SLIST_FIRST(lsp
))
529 /* This node had no children - skip it! */
532 if (!sysctl_sysctl_next_ls (lsp
, 0, 0, next
+1,
533 len
, level
+1, oidpp
))
538 if (oidp
->oid_number
< *name
)
541 if (oidp
->oid_number
> *name
) {
542 if ((oidp
->oid_kind
& CTLTYPE
) != CTLTYPE_NODE
)
544 if (oidp
->oid_handler
)
546 lsp
= (struct sysctl_oid_list
*)oidp
->oid_arg1
;
547 if (!sysctl_sysctl_next_ls (lsp
, name
+1, namelen
-1,
548 next
+1, len
, level
+1, oidpp
))
552 if ((oidp
->oid_kind
& CTLTYPE
) != CTLTYPE_NODE
)
555 if (oidp
->oid_handler
)
558 lsp
= (struct sysctl_oid_list
*)oidp
->oid_arg1
;
559 if (!sysctl_sysctl_next_ls (lsp
, name
+1, namelen
-1, next
+1,
560 len
, level
+1, oidpp
))
570 sysctl_sysctl_next(__unused
struct sysctl_oid
*oidp
, void *arg1
, int arg2
,
571 struct sysctl_req
*req
)
573 int *name
= (int *) arg1
;
574 u_int namelen
= arg2
;
576 struct sysctl_oid
*oid
;
577 struct sysctl_oid_list
*lsp
= &sysctl__children
;
578 int newoid
[CTL_MAXNAME
];
580 i
= sysctl_sysctl_next_ls (lsp
, name
, namelen
, newoid
, &j
, 1, &oid
);
583 error
= SYSCTL_OUT(req
, newoid
, j
* sizeof (int));
587 SYSCTL_NODE(_sysctl
, 2, next
, CTLFLAG_RD
, sysctl_sysctl_next
, "");
590 name2oid (char *name
, int *oid
, int *len
, struct sysctl_oid
**oidpp
)
593 struct sysctl_oid
*oidp
;
594 struct sysctl_oid_list
*lsp
= &sysctl__children
;
600 p
= name
+ strlen(name
) - 1 ;
606 for (p
= name
; *p
&& *p
!= '.'; p
++)
612 oidp
= SLIST_FIRST(lsp
);
614 while (oidp
&& *len
< CTL_MAXNAME
) {
615 if (strcmp(name
, oidp
->oid_name
)) {
616 oidp
= SLIST_NEXT(oidp
, oid_link
);
619 *oid
++ = oidp
->oid_number
;
628 if ((oidp
->oid_kind
& CTLTYPE
) != CTLTYPE_NODE
)
631 if (oidp
->oid_handler
)
634 lsp
= (struct sysctl_oid_list
*)oidp
->oid_arg1
;
635 oidp
= SLIST_FIRST(lsp
);
637 for (p
= name
; *p
&& *p
!= '.'; p
++)
647 sysctl_sysctl_name2oid(__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
,
648 __unused
int arg2
, struct sysctl_req
*req
)
651 int error
, oid
[CTL_MAXNAME
];
652 int len
= 0; /* set by name2oid() */
653 struct sysctl_oid
*op
= 0;
657 if (req
->newlen
>= MAXPATHLEN
) /* XXX arbitrary, undocumented */
658 return (ENAMETOOLONG
);
660 MALLOC(p
, char *,req
->newlen
+1, M_TEMP
, M_WAITOK
);
664 error
= SYSCTL_IN(req
, p
, req
->newlen
);
670 p
[req
->newlen
] = '\0';
672 error
= name2oid(p
, oid
, &len
, &op
);
679 error
= SYSCTL_OUT(req
, oid
, len
* sizeof *oid
);
683 SYSCTL_PROC(_sysctl
, 3, name2oid
, CTLFLAG_RW
|CTLFLAG_ANYBODY
|CTLFLAG_KERN
, 0, 0,
684 sysctl_sysctl_name2oid
, "I", "");
687 sysctl_sysctl_oidfmt(__unused
struct sysctl_oid
*oidp
, void *arg1
, int arg2
,
688 struct sysctl_req
*req
)
690 int *name
= (int *) arg1
, error
;
691 u_int namelen
= arg2
;
693 struct sysctl_oid
*oid
;
694 struct sysctl_oid_list
*lsp
= &sysctl__children
;
696 oid
= SLIST_FIRST(lsp
);
699 while (oid
&& indx
< CTL_MAXNAME
) {
700 if (oid
->oid_number
== name
[indx
]) {
702 if ((oid
->oid_kind
& CTLTYPE
) == CTLTYPE_NODE
) {
703 if (oid
->oid_handler
)
707 lsp
= (struct sysctl_oid_list
*)oid
->oid_arg1
;
708 oid
= SLIST_FIRST(lsp
);
715 oid
= SLIST_NEXT(oid
, oid_link
);
722 error
= SYSCTL_OUT(req
,
723 &oid
->oid_kind
, sizeof(oid
->oid_kind
));
725 error
= SYSCTL_OUT(req
, oid
->oid_fmt
,
726 strlen(oid
->oid_fmt
)+1);
731 SYSCTL_NODE(_sysctl
, 4, oidfmt
, CTLFLAG_RD
, sysctl_sysctl_oidfmt
, "");
734 * Default "handler" functions.
738 * Handle an int, signed or unsigned.
740 * a variable: point arg1 at it.
741 * a constant: pass it in arg2.
745 sysctl_handle_int(__unused
struct sysctl_oid
*oidp
, void *arg1
, int arg2
,
746 struct sysctl_req
*req
)
748 return sysctl_io_number(req
, arg1
? *(int*)arg1
: arg2
, sizeof(int), arg1
, NULL
);
752 * Handle a long, signed or unsigned. arg1 points to it.
756 sysctl_handle_long(__unused
struct sysctl_oid
*oidp
, void *arg1
,
757 __unused
int arg2
, struct sysctl_req
*req
)
761 return sysctl_io_number(req
, *(long*)arg1
, sizeof(long), arg1
, NULL
);
765 * Handle a quad, signed or unsigned. arg1 points to it.
769 sysctl_handle_quad(__unused
struct sysctl_oid
*oidp
, void *arg1
,
770 __unused
int arg2
, struct sysctl_req
*req
)
774 return sysctl_io_number(req
, *(long long*)arg1
, sizeof(long long), arg1
, NULL
);
778 * Expose an int value as a quad.
780 * This interface allows us to support interfaces defined
781 * as using quad values while the implementation is still
785 sysctl_handle_int2quad(__unused
struct sysctl_oid
*oidp
, void *arg1
,
786 __unused
int arg2
, struct sysctl_req
*req
)
794 val
= (long long)*(int *)arg1
;
795 error
= SYSCTL_OUT(req
, &val
, sizeof(long long));
797 if (error
|| !req
->newptr
)
800 error
= SYSCTL_IN(req
, &val
, sizeof(long long));
803 * Value must be representable; check by
804 * casting and then casting back.
807 if ((long long)newval
!= val
) {
810 *(int *)arg1
= newval
;
817 * Handle our generic '\0' terminated 'C' string.
819 * a variable string: point arg1 at it, arg2 is max length.
820 * a constant string: point arg1 at it, arg2 is zero.
824 sysctl_handle_string( __unused
struct sysctl_oid
*oidp
, void *arg1
, int arg2
,
825 struct sysctl_req
*req
)
827 return sysctl_io_string(req
, arg1
, arg2
, 0, NULL
);
831 * Handle any kind of opaque data.
832 * arg1 points to it, arg2 is the size.
836 sysctl_handle_opaque(__unused
struct sysctl_oid
*oidp
, void *arg1
, int arg2
,
837 struct sysctl_req
*req
)
839 return sysctl_io_opaque(req
, arg1
, arg2
, NULL
);
843 * Transfer functions to/from kernel space.
846 sysctl_old_kernel(struct sysctl_req
*req
, const void *p
, size_t l
)
852 if (i
> req
->oldlen
- req
->oldidx
)
853 i
= req
->oldlen
- req
->oldidx
;
855 bcopy((const void*)p
, CAST_DOWN(char *, (req
->oldptr
+ req
->oldidx
)), i
);
858 if (req
->oldptr
&& i
!= l
)
864 sysctl_new_kernel(struct sysctl_req
*req
, void *p
, size_t l
)
868 if (req
->newlen
- req
->newidx
< l
)
870 bcopy(CAST_DOWN(char *, (req
->newptr
+ req
->newidx
)), p
, l
);
876 kernel_sysctl(struct proc
*p
, int *name
, u_int namelen
, void *old
, size_t *oldlenp
, void *new, size_t newlen
)
879 struct sysctl_req req
;
884 bzero(&req
, sizeof req
);
887 req
.oldlen
= *oldlenp
;
889 req
.oldptr
= CAST_USER_ADDR_T(old
);
892 req
.newptr
= CAST_USER_ADDR_T(new);
894 req
.oldfunc
= sysctl_old_kernel
;
895 req
.newfunc
= sysctl_new_kernel
;
898 /* make the request */
899 error
= sysctl_root(0, name
, namelen
, &req
);
901 /* unlock memory if required */
903 vsunlock(req
.oldptr
, (user_size_t
)req
.oldlen
, B_WRITE
);
905 if (error
&& error
!= ENOMEM
)
909 *oldlenp
= req
.oldidx
;
915 * Transfer function to/from user space.
918 sysctl_old_user(struct sysctl_req
*req
, const void *p
, size_t l
)
924 if (req
->oldlen
- req
->oldidx
< l
)
927 if (i
> req
->oldlen
- req
->oldidx
)
928 i
= req
->oldlen
- req
->oldidx
;
930 error
= copyout((const void*)p
, (req
->oldptr
+ req
->oldidx
), i
);
935 if (req
->oldptr
&& i
< l
)
941 sysctl_new_user(struct sysctl_req
*req
, void *p
, size_t l
)
947 if (req
->newlen
- req
->newidx
< l
)
949 error
= copyin((req
->newptr
+ req
->newidx
), p
, l
);
955 * Traverse our tree, and find the right node, execute whatever it points
956 * at, and return the resulting error code.
960 sysctl_root(__unused
struct sysctl_oid
*oidp
, void *arg1
, int arg2
,
961 struct sysctl_req
*req
)
963 int *name
= (int *) arg1
;
964 u_int namelen
= arg2
;
967 struct sysctl_oid
*oid
;
968 struct sysctl_oid_list
*lsp
= &sysctl__children
;
970 funnel_t
*fnl
= NULL
;
971 boolean_t funnel_held
= FALSE
;
973 /* Get the read lock on the geometry */
974 lck_rw_lock_shared(sysctl_geometry_lock
);
976 oid
= SLIST_FIRST(lsp
);
979 while (oid
&& indx
< CTL_MAXNAME
) {
980 if (oid
->oid_number
== name
[indx
]) {
982 if (!(oid
->oid_kind
& CTLFLAG_LOCKED
))
986 if (oid
->oid_kind
& CTLFLAG_NOLOCK
)
988 if ((oid
->oid_kind
& CTLTYPE
) == CTLTYPE_NODE
) {
989 if (oid
->oid_handler
)
997 lsp
= (struct sysctl_oid_list
*)oid
->oid_arg1
;
998 oid
= SLIST_FIRST(lsp
);
1000 if (indx
!= namelen
)
1008 oid
= SLIST_NEXT(oid
, oid_link
);
1014 /* If writing isn't allowed */
1015 if (req
->newptr
&& (!(oid
->oid_kind
& CTLFLAG_WR
) ||
1016 ((oid
->oid_kind
& CTLFLAG_SECURE
) && securelevel
> 0))) {
1022 * If we're inside the kernel, the OID must be marked as kernel-valid.
1023 * XXX This mechanism for testing is bad.
1025 if ((req
->oldfunc
== sysctl_old_kernel
) && !(oid
->oid_kind
& CTLFLAG_KERN
))
1031 /* Most likely only root can write */
1032 if (!(oid
->oid_kind
& CTLFLAG_ANYBODY
) &&
1033 req
->newptr
&& req
->p
&&
1034 (error
= proc_suser(req
->p
)))
1037 if (!oid
->oid_handler
) {
1044 fnl
= spl_kernel_funnel();
1048 if ((oid
->oid_kind
& CTLTYPE
) == CTLTYPE_NODE
) {
1049 i
= (oid
->oid_handler
) (oid
,
1050 name
+ indx
, namelen
- indx
,
1053 i
= (oid
->oid_handler
) (oid
,
1054 oid
->oid_arg1
, oid
->oid_arg2
,
1062 splx_kernel_funnel(fnl
);
1066 lck_rw_done(sysctl_geometry_lock
);
1070 #ifndef _SYS_SYSPROTO_H_
1071 struct sysctl_args
{
1082 /* __sysctl(struct proc *p, struct sysctl_args *uap) */
1083 new_sysctl(struct proc
*p
, struct sysctl_args
*uap
)
1085 int error
, i
, name
[CTL_MAXNAME
];
1088 if (uap
->namelen
> CTL_MAXNAME
|| uap
->namelen
< 2)
1091 error
= copyin(CAST_USER_ADDR_T(uap
->name
), &name
, uap
->namelen
* sizeof(int));
1095 error
= userland_sysctl(p
, name
, uap
->namelen
,
1096 CAST_USER_ADDR_T(uap
->old
), uap
->oldlenp
,
1097 CAST_USER_ADDR_T(uap
->new), uap
->newlen
, &j
);
1098 if (error
&& error
!= ENOMEM
)
1101 i
= copyout(&j
, CAST_USER_ADDR_T(uap
->oldlenp
), sizeof(j
));
1109 * This is used from various compatibility syscalls too. That's why name
1110 * must be in kernel space.
1113 userland_sysctl(struct proc
*p
, int *name
, u_int namelen
, user_addr_t oldp
,
1114 size_t *oldlenp
, user_addr_t newp
, size_t newlen
,
1118 struct sysctl_req req
, req2
;
1120 bzero(&req
, sizeof req
);
1125 req
.oldlen
= *oldlenp
;
1133 req
.newlen
= newlen
;
1137 req
.oldfunc
= sysctl_old_user
;
1138 req
.newfunc
= sysctl_new_user
;
1143 error
= sysctl_root(0, name
, namelen
, &req2
);
1144 } while (error
== EAGAIN
);
1148 if (error
&& error
!= ENOMEM
)
1152 if (req
.oldptr
&& req
.oldidx
> req
.oldlen
)
1153 *retval
= req
.oldlen
;
1155 *retval
= req
.oldidx
;
1160 /* Non-standard BSDI extension - only present on their 4.3 net-2 releases */
1161 #define KINFO_BSDI_SYSINFO (101<<8)
1164 * Kernel versions of the userland sysctl helper functions.
1166 * These allow sysctl to be used in the same fashion in both
1167 * userland and the kernel.
1169 * Note that some sysctl handlers use copyin/copyout, which
1170 * may not work correctly.
1174 sysctl(int *name
, u_int namelen
, void *oldp
, size_t *oldlenp
, void *newp
, size_t newlen
)
1177 return(kernel_sysctl(current_proc(), name
, namelen
, oldp
, oldlenp
, newp
, newlen
));
1181 sysctlnametomib(const char *name
, int *mibp
, size_t *sizep
)
1185 char *non_const_name
;
1188 * NOTE: This cast is safe because the service node does not modify
1189 * the contents of the string as part of its operation.
1191 non_const_name
= __CAST_AWAY_QUALIFIER(name
, const, char *);
1193 /* magic service node */
1197 /* look up OID for name */
1198 *sizep
*= sizeof(int);
1199 error
= sysctl(oid
, 2, mibp
, sizep
, non_const_name
, strlen(name
));
1200 *sizep
/= sizeof(int);
1206 sysctlbyname(const char *name
, void *oldp
, size_t *oldlenp
, void *newp
, size_t newlen
)
1208 int oid
[CTL_MAXNAME
+ 2];
1212 /* look up the OID */
1213 oidlen
= CTL_MAXNAME
;
1214 error
= sysctlnametomib(name
, oid
, &oidlen
);
1216 /* now use the OID */
1218 error
= sysctl(oid
, oidlen
, oldp
, oldlenp
, newp
, newlen
);