]> git.saurik.com Git - apple/xnu.git/blob - bsd/kern/kern_newsysctl.c
xnu-792.18.15.tar.gz
[apple/xnu.git] / bsd / kern / kern_newsysctl.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
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
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
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>
75 #include <sys/proc_internal.h>
76 #include <sys/systm.h>
77
78 #include <bsm/audit_kernel.h>
79
80 /*
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;
85 */
86
87 extern struct sysctl_oid *newsysctl_list[];
88 extern struct sysctl_oid *machdep_sysctl_list[];
89
90
91 static void
92 sysctl_sysctl_debug_dump_node(struct sysctl_oid_list *l, int i);
93
94
95
96 /*
97 * Locking and stats
98 */
99 static struct sysctl_lock {
100 int sl_lock;
101 int sl_want;
102 int sl_locked;
103 } memlock;
104
105 /*
106 * XXX this does not belong here
107 */
108 static funnel_t *
109 spl_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
122 static void
123 splx_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
132 static int sysctl_root SYSCTL_HANDLER_ARGS;
133
134 struct 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
142 void 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;
148 funnel_t *fnl;
149
150 fnl = spl_kernel_funnel();
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);
181
182 splx_kernel_funnel(fnl);
183 }
184
185 void sysctl_unregister_oid(struct sysctl_oid *oidp)
186 {
187 funnel_t *fnl;
188
189 fnl = spl_kernel_funnel();
190 SLIST_REMOVE(oidp->oid_parent, oidp, sysctl_oid, oid_link);
191 splx_kernel_funnel(fnl);
192 }
193
194 /*
195 * Bulk-register all the oids in a linker_set.
196 */
197 void 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
205 void 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
218 void sysctl_register_fixed()
219 {
220 int i;
221
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]);
227 }
228 }
229
230 /*
231 * Register the kernel's oids on startup.
232 */
233 struct linker_set sysctl_set;
234
235 void sysctl_register_all(void *arg)
236 {
237 sysctl_register_set(&sysctl_set);
238 }
239
240 SYSINIT(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
260 static void
261 sysctl_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
298 static int
299 sysctl_sysctl_debug SYSCTL_HANDLER_ARGS
300 {
301 sysctl_sysctl_debug_dump_node(&sysctl__children, 0);
302 return ENOENT;
303 }
304
305 SYSCTL_PROC(_sysctl, 0, debug, CTLTYPE_STRING|CTLFLAG_RD,
306 0, 0, sysctl_sysctl_debug, "-", "");
307
308 static int
309 sysctl_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;
316 char tempbuf[10];
317
318 while (namelen) {
319 if (!lsp) {
320 snprintf(tempbuf,sizeof(tempbuf),"%d",*name);
321 if (req->oldidx)
322 error = SYSCTL_OUT(req, ".", 1);
323 if (!error)
324 error = SYSCTL_OUT(req, tempbuf, strlen(tempbuf));
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
361 SYSCTL_NODE(_sysctl, 1, name, CTLFLAG_RD, sysctl_sysctl_name, "");
362
363 static int
364 sysctl_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
418 static int
419 sysctl_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
435 SYSCTL_NODE(_sysctl, 2, next, CTLFLAG_RD, sysctl_sysctl_next, "");
436
437 static int
438 name2oid (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
494 static int
495 sysctl_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
506 MALLOC(p, char *,req->newlen+1, M_TEMP, M_WAITOK);
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
529 SYSCTL_PROC(_sysctl, 3, name2oid, CTLFLAG_RW|CTLFLAG_ANYBODY|CTLFLAG_KERN, 0, 0,
530 sysctl_sysctl_name2oid, "I", "");
531
532 static int
533 sysctl_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;
564 found:
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
576 SYSCTL_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
589 int
590 sysctl_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));
606
607 if (error == 0)
608 AUDIT_ARG(value, *(int *)arg1);
609 return (error);
610 }
611
612 /*
613 * Handle a long, signed or unsigned. arg1 points to it.
614 */
615
616 int
617 sysctl_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
632 /*
633 * Handle a quad, signed or unsigned. arg1 points to it.
634 */
635
636 int
637 sysctl_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 */
659 int
660 sysctl_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
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
697 int
698 sysctl_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
723 int
724 sysctl_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.
740 */
741 static int
742 sysctl_old_kernel(struct sysctl_req *req, const void *p, size_t l)
743 {
744 size_t i = 0;
745
746 if (req->oldptr) {
747 i = l;
748 if (i > req->oldlen - req->oldidx)
749 i = req->oldlen - req->oldidx;
750 if (i > 0)
751 bcopy((void*)p, CAST_DOWN(char *, (req->oldptr + req->oldidx)), i);
752 }
753 req->oldidx += l;
754 if (req->oldptr && i != l)
755 return (ENOMEM);
756 return (0);
757 }
758
759 static int
760 sysctl_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);
766 bcopy(CAST_DOWN(char *, (req->newptr + req->newidx)), p, l);
767 req->newidx += l;
768 return (0);
769 }
770
771 int
772 kernel_sysctl(struct proc *p, int *name, u_int namelen, void *old, size_t *oldlenp, void *new, size_t newlen)
773 {
774 int error = 0;
775 struct sysctl_req req;
776 funnel_t *fnl;
777
778 /*
779 * Construct request.
780 */
781 bzero(&req, sizeof req);
782 req.p = p;
783 if (oldlenp)
784 req.oldlen = *oldlenp;
785 if (old)
786 req.oldptr = CAST_USER_ADDR_T(old);
787 if (newlen) {
788 req.newlen = newlen;
789 req.newptr = CAST_USER_ADDR_T(new);
790 }
791 req.oldfunc = sysctl_old_kernel;
792 req.newfunc = sysctl_new_kernel;
793 req.lock = 1;
794
795 /*
796 * Locking. Tree traversal always begins with the kernel funnel held.
797 */
798 fnl = spl_kernel_funnel();
799
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
808 /* make the request */
809 error = sysctl_root(0, name, namelen, &req);
810
811 /* unlock memory if required */
812 if (req.lock == 2)
813 vsunlock(req.oldptr, (user_size_t)req.oldlen, B_WRITE);
814
815 memlock.sl_lock = 0;
816
817 if (memlock.sl_want) {
818 memlock.sl_want = 0;
819 wakeup((caddr_t)&memlock);
820 }
821
822 /*
823 * Undo locking.
824 */
825 splx_kernel_funnel(fnl);
826
827 if (error && error != ENOMEM)
828 return (error);
829
830 if (oldlenp)
831 *oldlenp = req.oldidx;
832
833 return (error);
834 }
835
836 /*
837 * Transfer function to/from user space.
838 */
839 static int
840 sysctl_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)
852 error = copyout((void*)p, (req->oldptr + req->oldidx), i);
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
862 static int
863 sysctl_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);
871 error = copyin((req->newptr + req->newidx), p, l);
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
881 int
882 sysctl_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;
916 found:
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
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
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
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
951 return (i);
952 }
953
954 #ifndef _SYS_SYSPROTO_H_
955 struct 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
965 int
966 /* __sysctl(struct proc *p, struct sysctl_args *uap) */
967 new_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
975 error = copyin(CAST_USER_ADDR_T(uap->name), &name, uap->namelen * sizeof(int));
976 if (error)
977 return (error);
978
979 error = userland_sysctl(p, name, uap->namelen,
980 CAST_USER_ADDR_T(uap->old), uap->oldlenp, 0,
981 CAST_USER_ADDR_T(uap->new), uap->newlen, &j);
982 if (error && error != ENOMEM)
983 return (error);
984 if (uap->oldlenp) {
985 i = copyout(&j, CAST_USER_ADDR_T(uap->oldlenp), sizeof(j));
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 */
996 int
997 userland_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)
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 {
1012 error = copyin(CAST_USER_ADDR_T(oldlenp), &req.oldlen, sizeof(*oldlenp));
1013 if (error)
1014 return (error);
1015 }
1016 }
1017
1018 if (oldp) {
1019 req.oldptr = oldp;
1020 }
1021
1022 if (newlen) {
1023 req.newlen = newlen;
1024 req.newptr = newp;
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 }
1049
1050 /* Non-standard BSDI extension - only present on their 4.3 net-2 releases */
1051 #define KINFO_BSDI_SYSINFO (101<<8)
1052
1053 /*
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.
1061 */
1062
1063 static int
1064 sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, size_t newlen)
1065 {
1066
1067 return(kernel_sysctl(current_proc(), name, namelen, oldp, oldlenp, newp, newlen));
1068 }
1069
1070 static int
1071 sysctlnametomib(const char *name, int *mibp, size_t *sizep)
1072 {
1073 int oid[2];
1074 int error;
1075
1076 /* magic service node */
1077 oid[0] = 0;
1078 oid[1] = 3;
1079
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 }
1086
1087 int
1088 sysctlbyname(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;
1093
1094 /* look up the OID */
1095 oidlen = CTL_MAXNAME;
1096 error = sysctlnametomib(name, oid, &oidlen);
1097
1098 /* now use the OID */
1099 if (error == 0)
1100 error = sysctl(oid, oidlen, oldp, oldlenp, newp, newlen);
1101 return(error);
1102 }
1103