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