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